Search code examples
laraveleloquentlaravel-4polymorphismmany-to-many

How to use morphtomany


I'm trying to create a tagging system and now I got two table as the picture below

tags enter image description here

taggables

enter image description here

I would like to tag the Journal and id based on the `tag_id. However, the journal always create a new record in the taggables table.

Here is my model relationship

Tag

class Tag extends Model
    {
       public function purchases()
        {
        return $this
            ->morphedByMany('Purchase', 'taggable');
        }

       public function taggables()
       {
        return $this->hasMany('Taggable');
       }

    }

Purchase

class Purchase extends Model
    {
        public function tags()
        {
            return $this
                ->morphToMany('Tag', 'taggable');
        }
    }

Journal

class Journal extends Model
{
    public function tags()
    {
        return $this
            ->morphToMany('Tag', 'taggable');
    }
}

Solution

  • If I understood correctly you are trying to use tags for journals and purchases at the same time.

    Then your table structure should be something like:

    journals(id, ...)
    purchases(id, ...)
    tags(id, name)
    taggables(id, tag_id, taggable_id, taggable_type)

    Then the models that can be tagged should both have a method to retrive their tags:

    app/Journal.php

    // namespace and use statements
    
    class Journal extends Model
    {
        public function tags()
        {
            return $this->morphToMany('App\Tag', 'taggable');
        }
    }
    

    app/Purchase.php

    // namespace and use statements
    
    class Purchase extends Model
    {
        public function tags()
        {
            return $this->morphToMany('App\Tag', 'taggable');
        }
    }
    

    The your tag model that can be applied to both Purchase and Journal should have N methods, where N is the number of different models you are connecting through your polymorphic relation, in this example N=2 (one method to retrive purchases from a tag, and one method to retrive journals from a tag).

    app/Tag.php

    // namespace and use statements
    
    class Tag extends Model
    {
        public function journals()
        {
            return $this->morphedByMany('App\Journals', 'taggable');
        }
    
        public function purchases()
        {
            return $this->morphedByMany('App\Purchase', 'taggable');
        }
    }
    

    After the relations are set you can retrive the tags assigned to a journal or a purchase:

    $journal = \App\Journal::first();
    
    foreach ($journal->tags as $tag) {
        // ...
    }
    

    or retrive all the journals or purchases linked to a specific tag:

    $tag = \App\Tag::first();
    
    // $tag->journals will contain the journals model instances linked to the current tag
    // $tag->purchases will contain the purchases model instances linked to the current tag
    

    Note: to define relationships use the FQDN of the related class, for instance: 'App\Tag' instead of 'Tag', otherwise the class would not be found by the autoloader.