search
HomeBackend DevelopmentPHP TutorialRe-Introducing Eloquent's Polymorphic Relationships

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>

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>

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>

{some_timestamp}_create_songs_table.php

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

{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');
    });
}

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();
    });
}

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>

app/Album.php

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

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');
    }
}
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');
    }
}

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>

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();
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>

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>

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();
    });
}

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>

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>

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();
    });
}

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');
    });
}

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();
    });
}

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
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
PHP's Current Status: A Look at Web Development TrendsPHP's Current Status: A Look at Web Development TrendsApr 13, 2025 am 12:20 AM

PHP remains important in modern web development, especially in content management and e-commerce platforms. 1) PHP has a rich ecosystem and strong framework support, such as Laravel and Symfony. 2) Performance optimization can be achieved through OPcache and Nginx. 3) PHP8.0 introduces JIT compiler to improve performance. 4) Cloud-native applications are deployed through Docker and Kubernetes to improve flexibility and scalability.

PHP vs. Other Languages: A ComparisonPHP vs. Other Languages: A ComparisonApr 13, 2025 am 12:19 AM

PHP is suitable for web development, especially in rapid development and processing dynamic content, but is not good at data science and enterprise-level applications. Compared with Python, PHP has more advantages in web development, but is not as good as Python in the field of data science; compared with Java, PHP performs worse in enterprise-level applications, but is more flexible in web development; compared with JavaScript, PHP is more concise in back-end development, but is not as good as JavaScript in front-end development.

PHP vs. Python: Core Features and FunctionalityPHP vs. Python: Core Features and FunctionalityApr 13, 2025 am 12:16 AM

PHP and Python each have their own advantages and are suitable for different scenarios. 1.PHP is suitable for web development and provides built-in web servers and rich function libraries. 2. Python is suitable for data science and machine learning, with concise syntax and a powerful standard library. When choosing, it should be decided based on project requirements.

PHP: A Key Language for Web DevelopmentPHP: A Key Language for Web DevelopmentApr 13, 2025 am 12:08 AM

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

PHP: The Foundation of Many WebsitesPHP: The Foundation of Many WebsitesApr 13, 2025 am 12:07 AM

The reasons why PHP is the preferred technology stack for many websites include its ease of use, strong community support, and widespread use. 1) Easy to learn and use, suitable for beginners. 2) Have a huge developer community and rich resources. 3) Widely used in WordPress, Drupal and other platforms. 4) Integrate tightly with web servers to simplify development deployment.

Beyond the Hype: Assessing PHP's Role TodayBeyond the Hype: Assessing PHP's Role TodayApr 12, 2025 am 12:17 AM

PHP remains a powerful and widely used tool in modern programming, especially in the field of web development. 1) PHP is easy to use and seamlessly integrated with databases, and is the first choice for many developers. 2) It supports dynamic content generation and object-oriented programming, suitable for quickly creating and maintaining websites. 3) PHP's performance can be improved by caching and optimizing database queries, and its extensive community and rich ecosystem make it still important in today's technology stack.

What are Weak References in PHP and when are they useful?What are Weak References in PHP and when are they useful?Apr 12, 2025 am 12:13 AM

In PHP, weak references are implemented through the WeakReference class and will not prevent the garbage collector from reclaiming objects. Weak references are suitable for scenarios such as caching systems and event listeners. It should be noted that it cannot guarantee the survival of objects and that garbage collection may be delayed.

Explain the __invoke magic method in PHP.Explain the __invoke magic method in PHP.Apr 12, 2025 am 12:07 AM

The \_\_invoke method allows objects to be called like functions. 1. Define the \_\_invoke method so that the object can be called. 2. When using the $obj(...) syntax, PHP will execute the \_\_invoke method. 3. Suitable for scenarios such as logging and calculator, improving code flexibility and readability.

See all articles

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

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment