skip to Main Content

In my Laravel app, I have User, List and ListItem models, with a one-to-many relationship between User and List and many-to-many relationships between User and ListItem and between List and ListItem. Each User should be able to tag the ListItems on each List separately, so that ListItem 1 can have different tags on List A and List B. My lists_listitems pivot table has a column "tags" but I don’t know how to define a Tag model on a relationship.

I thought about simplifying the problem by creating a Tag model with a many-to-many relationship with ListItems, but as all Users have access to all ListItems in the data base, a ListItem’s Tags would then be visible to all Users. And if I would try to make the Tags visible only to one User, I would have the same problem (just for the listitems_user pivot table instead of the lists_listitmes one).
I searched the docs and the web but did not get any useful hits, which might be due to Tags being a very common example for a many-to-many relationship, without the additional complication that my app necessitates. Is it even possible to tag relationships in Laravel?

2

Answers


  1. I would make an additional Tag model so the entities would be Tag, User, List, ListItem, with one pivot list_item_user_tags.

    I would leave the users table as it is, then the
    tags table – id, name, user_id (so the tags are user-specific);
    lists table – id, name;
    list_items table – id, name; list_item_user_tags table – id, list_id, list_item_id, tag_id, user_id.

    Login or Signup to reply.
  2. If in the system you are considering, tags are fixed and can be defined as Enums, I suggest you consider a table with columns of user_id, list_id, list_item_id and a tag column whose content is Enum. With this work, every time you access the array of lists or item lists, you can easily have a pivot for the label inside your relationship. The relationship codes for the proposed table will be as follows:

    // User model
    public function lists(){
        return $this->hasMany(List::class, 'list_id');
    }
    public function list_items(){
        return $this->belongsToMany(ListItem::class, 'pivot_table', 'user_id', 'list_item_id')
                    ->withPivot(['list_id', 'tag']);
    }
    
    //for attach new tag to a list item in a list
    $user->list_items()->attach($list_item_id, ['list_id' => $list_id, 'tag' => $tag]);
    
    //for getting list items with tags
    $list_items = $user->list_items()->get();
    foreach($list_items as $list_item){
        $tag = $list_item->pivot->tag;
        $list_id= $list_item->pivot->list_id;
    }
    

    But if the tags could be defined by the user and each user had his own tags, you should also define a model for the Tag. And in the previous proposed table, use the id of this tag instead of the enum. In this case, the relations will be like this:

    // User model
    public function lists(){
        return $this->hasMany(List::class, 'list_id');
    }
    public function list_items(){
        return $this->belongsToMany(ListItem::class, 'pivot_table', 'user_id', 'list_item_id')
                    ->withPivot(['list_id', 'tag_id']);
    }
    public function tags(){
        return $this->hasMany(Tag::class, 'tag_id');
    }
    
    //Tag model
    public function user(){
        return $this->belongsTo(User::class, 'user_id');
    }
    public function list_items(){
        return $this->belongsToMany(ListItem::class, 'pivot_table', 'tag_id', 'list_item_id')
                    ->withPivot(['user_id', 'list_id']);
    }
    
    //ListItem Model
    public function list(){
        return $this->belongsTo(List::class, 'list_id');
    }
    
    public function users(){
        return $this->belongsToMany(User::class, 'pivot_table', 'list_item_id', 'user_id')
                    ->withPivot(['list_id', 'tag_id']);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search