Table of Contents
What we will build
Generate models and migration
Retrieval Relationship
Custom polymorphic type
Conclusion
FAQs about Eloquent's polymorphic relationships
What are the benefits of using polymorphic relationships in Laravel?
How to set polymorphic relationships in Laravel?
Can you provide an example of polymorphic relationships in Laravel?
How to use polymorphic relationships to retrieve related records?
How to save related records using polymorphic relationships?
What are some common use cases for polymorphic relationships?
What are the limitations or disadvantages of using polymorphic relationships?
How to delete relevant records in polymorphic relationships?
Can I use polymorphic relationships with many-to-many relationships?
How to deal with polymorphic relationships in database migration?
Home Backend Development PHP Tutorial Re-Introducing Eloquent's Polymorphic Relationships

Re-Introducing Eloquent's Polymorphic Relationships

Feb 09, 2025 pm 12:17 PM

Re-Introducing Eloquent's Polymorphic Relationships

Core points

  • Laravel's polymorphic association allows a model to belong to multiple other models on one association. This simplifies the database structure, makes the code easier to maintain, and allows for more dynamic and flexible data relationships.
  • Setting up polymorphic associations in Laravel involves defining associations in the Eloquent model. The morphTo method is used to receive a polymorphic associated model, while the morphMany or morphOne method is used to a model associated with other models.
  • Laravel's MorphMap method can be used to instruct Eloquent to use a custom name instead of a class name for each model. This is helpful in case of model namespace changes or namespaces that are too long.
  • Laravel supports many-to-many polymorphic relationships, allowing a model to belong to multiple models on a many-to-many basis. This is especially useful in complex applications.

This article was peer-reviewed by Younes Rafie. Thanks to all the peer reviewers of SitePoint to make the content of SitePoint perfect!


Re-Introducing Eloquent's Polymorphic Relationships

You may have used different types of relationships between models or database tables, such as common in Laravel: one-to-one, one-to-many, many-to-many, and has-many-through. But there is another less common type: polymorphic association. So what is polymorphic association?

Polymorphic association refers to a model that can belong to multiple other models in one association.

To illustrate this, let's create a fictional scene where we have Topic and Post models. Users can leave comments in topics and posts. Using polymorphic relationships, we can use a single comments table for both cases. Surprisingly, right? This seems a bit impractical because ideally we have to create the post_comments table and the topic_comments table to distinguish comments. Using polymorphic relationships, we do not need two tables. Let's understand polymorphic relationships through a practical example.

What we will build

We will create a demo music app that contains songs and albums. In this app, we can like songs and albums. Using polymorphic relationships, we will use a single upvotes table for both cases. First, let's examine the table structure required to build this relationship:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>
Copy after login
Copy after login
Copy after login
Copy after login

Let's discuss the upvoteable_id and upvoteable_type columns, which may seem a little strange to those who have not used polymorphic relationships before. The upvoteable_id column will contain the ID value of the album or song, while the upvoteable_type column will contain the class name that owns the model. The upvoteable_type column is how the ORM determines which "type" to return to own the model when accessing the upvoteable relationship.

Generate models and migration

I assume you already have a running Laravel application. If not, this advanced quick-start course may be helpful. Let's first create three models and migrations, and then edit the migrations to suit our needs.

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>
Copy after login
Copy after login
Copy after login
Copy after login

Note that passing the -m flag when creating a model will also generate migrations associated with these models. Let's adjust the up methods in these migrations to get the desired table structure:

{some_timestamp}_create_albums_table.php

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>
Copy after login
Copy after login
Copy after login

{some_timestamp}_create_songs_table.php

public function up()
{
    Schema::create('albums', function (Blueprint $table) {
       $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}
Copy after login
Copy after login
Copy after login

{some_timestamp}_create_upvotes_table.php

public function up()
{
    Schema::create('songs', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->integer('album_id')->unsigned()->index();
        $table->timestamps();

        $table->foreign('album_id')->references('id')->on('albums')->onDelete('cascade');
    });
}
Copy after login
Copy after login

Now, we can run the artisan migrate command to create these three tables:

public function up()
{
    Schema::create('upvotes', function (Blueprint $table) {
        $table->increments('id');
        $table->morphs('upvoteable'); // 添加无符号整数 upvoteable_id 和字符串 upvoteable_type
        $table->timestamps();
    });
}
Copy after login
Copy after login

Let's configure our model to pay attention to the polymorphic relationship between albums, songs and likes:

app/Upvote.php

<code>php artisan migrate</code>
Copy after login

app/Album.php

[...]
class Upvote extends Model
{
    /**
     * 获取所有拥有模型。
     */
    public function upvoteable()
    {
        return $this->morphTo();
    }
}
Copy after login

app/Song.php

class Album extends Model
{
    protected $fillable = ['name'];

    public function songs()
    {
        return $this->hasMany(Song::class);
    }

    public function upvotes()
    {
        return $this->morphMany(Upvote::class, 'upvoteable');
    }
}
Copy after login
The

method in the upvotes Album and Song models defines the polymorphic one-to-many relationship between these models and the Upvote model and will help us get all the likes of that particular model instance.

After defining the relationship, we can now try the application to better understand how polymorphic relationships work. We won't create any views for this app, we will only try our app from the console.

If you consider the controller and where we should place the like method, I suggest creating an AlbumUpvoteController and a SongUpvoteController. In this way, when we deal with polymorphic relationships, we can strictly connect things to the object we are operating on. In our case, we can like the album and song. Likes are not an album or a song. Also, it's not a general like, which is the opposite of how we have UpvotesController in most one-to-many relationships. Hope this makes sense.

Let's start the console:

class Song extends Model
{
    protected $fillable = ['title', 'album_id'];

    public function album()
    {
        return $this->belongsTo(Album::class);
    }

    public function upvotes()
    {
        return $this->morphMany(Upvote::class, 'upvoteable');
    }
}
Copy after login

Retrieval Relationship

Now that we have some data ready, we can access our relationships through our model. Here is a screenshot of the data in the upvotes table:

Re-Introducing Eloquent's Polymorphic Relationships

To access all the likes of the album, we can use upvotes Dynamic attribute:

<code>php artisan tinker
>>> $album = App\Album::create(['name' => 'More Life']);
>>> $song = App\Song::create(['title' => 'Free smoke', 'album_id' => 1]);
>>> $upvote1 = new App\Upvote;
>>> $upvote2 = new App\Upvote;
>>> $upvote3 = new App\Upvote;
>>> $album->upvotes()->save($upvote1);
>>> $song->upvotes()->save($upvote2);
>>> $album->upvotes()->save($upvote3);</code>
Copy after login

can also retrieve the owner of a polymorphic relationship from the polymorphic model by accessing the name of the method that performs the call to morphTo. In our case, that is the upvoteable method on the Upvote model. Therefore, we will access the method as a dynamic property:

$album = App\Album::find(1);
$upvotes = $album->upvotes;
$upvotescount = $album->upvotes->count();
Copy after login
The

relation on the upvoteableUpvote model will return an Album instance, as this like is owned by the instance of the Album instance.

Because we can get the number of likes for a song or album, we can sort the song or album based on the likes on the view. That's how music charts work.

For songs, we will get likes like this:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>
Copy after login
Copy after login
Copy after login
Copy after login

Custom polymorphic type

By default, Laravel will use fully qualified class names to store the types of the relevant model. For example, in the above example, Upvote might belong to Album or Song, and the default upvoteable_type is App\Album or App\Song respectively.

However, this has a big drawback. What if the namespace of the Album model changes? We will have to do some sort of migration to rename all occurrences in the upvotes table. This is a little tricky! What happens if the namespace is long (e.g. App\Models\Data\Topics\Something\SomethingElse)? This means we have to set a very long maximum length on the column. This is where the MorphMap method can help us.

The "morphMap" method will instruct Eloquent to use a custom name for each model, not the class name:

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>
Copy after login
Copy after login
Copy after login

We can register morphMap in the boot function of the AppServiceProvider, or create a separate service provider. In order for the new changes to take effect, we must run the composer dump-autoload command. So now we can add this new like record:

public function up()
{
    Schema::create('albums', function (Blueprint $table) {
       $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}
Copy after login
Copy after login
Copy after login

It behaves exactly the same as the previous example.

Conclusion

Even if you may have never encountered a situation where you need to use polymorphic relationships, that day may eventually come. The advantage of using Laravel is that handling this situation is very easy and it takes no need to do any model association tricks to get things working. Laravel even supports many-to-many polymorphic relationships. You can read more about it here.

I hope you have now understood polymorphic relationships and what may be needed for these types of relationships. Another slightly more advanced example of polymorphic relationships is here. If you find this helpful, please share it with your friends and don't forget to click the Like button. Feel free to leave your thoughts in the comment section below!

FAQs about Eloquent's polymorphic relationships

What are the benefits of using polymorphic relationships in Laravel?

Polymorphic relations in Laravel provide a flexible and efficient way to process related data between different models. They allow a model to belong to multiple other types of models in one association. This means you can have a single unique identifier list of all relevant data regardless of their type. This can greatly simplify your database structure and make your code easier to maintain. It also allows for more dynamic and flexible data relationships, which are particularly useful in complex applications.

How to set polymorphic relationships in Laravel?

Setting up polymorphic relationships in Laravel involves defining relationships in the Eloquent model. First, you need to define the relationship on the model that will receive the polymorphic relationship. This is done using the morphTo method. Then, on the model that will be associated with the other models, use the morphMany or morphOne method according to whether the relationship is one-to-many or one-to-one.

Can you provide an example of polymorphic relationships in Laravel?

Of course, let's consider a blog platform where both posts and users can have comments. In this case, the Comment model will have a polymorphic relationship with the Post and User models. Here is how to define this relationship:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>
Copy after login
Copy after login
Copy after login
Copy after login

You can retrieve relevant records in polymorphic relationships like you would with any other Eloquent relationship. For example, if you want to retrieve all comments from a post, you can do this:

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>
Copy after login
Copy after login
Copy after login

Save related records in polymorphic relationships also similar to other Eloquent relationships. You can associate the model using the associate method and save the model. Here is an example:

public function up()
{
    Schema::create('albums', function (Blueprint $table) {
       $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}
Copy after login
Copy after login
Copy after login

What are some common use cases for polymorphic relationships?

Polymorphic relations are particularly useful in situations where the model can belong to multiple other types of models. Some common use cases include comments that can belong to posts and users, tags that can be applied to multiple types of content, and images or files that can be attached to various types of entities.

What are the limitations or disadvantages of using polymorphic relationships?

While polymorphic relationships provide a lot of flexibility, they may also be more complex and harder to set up and manage than standard Eloquent relationships. They also support all features of standard relationships, such as desire to load constraints.

How to delete relevant records in polymorphic relationships?

You can use the delete method on the relationship to delete relevant records in a polymorphic relationship. For example, to delete all comments from a post, you can do this:

public function up()
{
    Schema::create('songs', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->integer('album_id')->unsigned()->index();
        $table->timestamps();

        $table->foreign('album_id')->references('id')->on('albums')->onDelete('cascade');
    });
}
Copy after login
Copy after login

Can I use polymorphic relationships with many-to-many relationships?

Yes, Laravel supports many-to-many polymorphic relationships through the morphToMany and morphedByMany methods. This allows a model to belong to multiple models on a many-to-many basis.

How to deal with polymorphic relationships in database migration?

In a database migration, you usually add two columns to the table that will receive polymorphic relationships: one for the related model ID and the other for the related model type. Laravel provides a convenient morphs method to add these columns:

public function up()
{
    Schema::create('upvotes', function (Blueprint $table) {
        $table->increments('id');
        $table->morphs('upvoteable'); // 添加无符号整数 upvoteable_id 和字符串 upvoteable_type
        $table->timestamps();
    });
}
Copy after login
Copy after login

This adds commentable_id and commentable_type columns to the table.

The above is the detailed content of Re-Introducing Eloquent's Polymorphic Relationships. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1655
14
PHP Tutorial
1252
29
C# Tutorial
1226
24
Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

How does session hijacking work and how can you mitigate it in PHP? How does session hijacking work and how can you mitigate it in PHP? Apr 06, 2025 am 12:02 AM

Session hijacking can be achieved through the following steps: 1. Obtain the session ID, 2. Use the session ID, 3. Keep the session active. The methods to prevent session hijacking in PHP include: 1. Use the session_regenerate_id() function to regenerate the session ID, 2. Store session data through the database, 3. Ensure that all session data is transmitted through HTTPS.

What is REST API design principles? What is REST API design principles? Apr 04, 2025 am 12:01 AM

RESTAPI design principles include resource definition, URI design, HTTP method usage, status code usage, version control, and HATEOAS. 1. Resources should be represented by nouns and maintained at a hierarchy. 2. HTTP methods should conform to their semantics, such as GET is used to obtain resources. 3. The status code should be used correctly, such as 404 means that the resource does not exist. 4. Version control can be implemented through URI or header. 5. HATEOAS boots client operations through links in response.

What are anonymous classes in PHP and when might you use them? What are anonymous classes in PHP and when might you use them? Apr 04, 2025 am 12:02 AM

The main function of anonymous classes in PHP is to create one-time objects. 1. Anonymous classes allow classes without names to be directly defined in the code, which is suitable for temporary requirements. 2. They can inherit classes or implement interfaces to increase flexibility. 3. Pay attention to performance and code readability when using it, and avoid repeatedly defining the same anonymous classes.

How do you handle exceptions effectively in PHP (try, catch, finally, throw)? How do you handle exceptions effectively in PHP (try, catch, finally, throw)? Apr 05, 2025 am 12:03 AM

In PHP, exception handling is achieved through the try, catch, finally, and throw keywords. 1) The try block surrounds the code that may throw exceptions; 2) The catch block handles exceptions; 3) Finally block ensures that the code is always executed; 4) throw is used to manually throw exceptions. These mechanisms help improve the robustness and maintainability of your code.

Explain different error types in PHP (Notice, Warning, Fatal Error, Parse Error). Explain different error types in PHP (Notice, Warning, Fatal Error, Parse Error). Apr 08, 2025 am 12:03 AM

There are four main error types in PHP: 1.Notice: the slightest, will not interrupt the program, such as accessing undefined variables; 2. Warning: serious than Notice, will not terminate the program, such as containing no files; 3. FatalError: the most serious, will terminate the program, such as calling no function; 4. ParseError: syntax error, will prevent the program from being executed, such as forgetting to add the end tag.

What is the difference between include, require, include_once, require_once? What is the difference between include, require, include_once, require_once? Apr 05, 2025 am 12:07 AM

In PHP, the difference between include, require, include_once, require_once is: 1) include generates a warning and continues to execute, 2) require generates a fatal error and stops execution, 3) include_once and require_once prevent repeated inclusions. The choice of these functions depends on the importance of the file and whether it is necessary to prevent duplicate inclusion. Rational use can improve the readability and maintainability of the code.

PHP and Python: Comparing Two Popular Programming Languages PHP and Python: Comparing Two Popular Programming Languages Apr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

See all articles