I am using Laravel to create a music search/discovery website. In short Artists have many Albums which have many Tracks. A User has many Tags associated with the Tracks. TAGGING CAN ONLY BE DONE ON TRACKS, NOT ALBUMS OR ARTISTS.
A user visits the website and can search for a set of tags e.g. "Happy", "Party", "School". A list of tracks is returned along with some other details.
The tracks are tagged in the first place by users. A user should be able to see all the tracks that they have tagged and be able to search/ filter based on tags too.
With my current setup (see table structure below) there is no way to tell which user tagged a particular track. I am thinking about merging the two tables tag_track and tag_user into one. The new table would have a structure of:
Tag_ID
Track_ID
User_ID
User_ID (UNI)
User_Name
Artist_ID (UNI)
Artist_Name
Album_ID (UNI)
Album_Title
Artist_ID
Track_ID (UNI)
Track_title
Album_ID
Tag_ID (UNI)
Tag_text (UNI)
Tag_ID
Track_ID
Tag_ID
User_ID
Has many Tlbums
Belongs to Album Has many Tracks
Belongs to Album Has many Tracks
Belongs to many Tags
Belongs to many Tracks Belongs to many Users
You're right about the pivot table. It must contain 3 keys, as in this situation tags can't exist without a user or a track. So it's a relationship between 3 models.
So here's all you need (I'm skipping artist and album relations ofc):
// pivot table tag_track_user: tag_id, track_id, user_id, id, timestamps
// Tag model
public function users()
{
// by default only 2 keys are on the pivot, so lets add the third
return $this->belongsToMany('User', 'tag_track_user')->withPivot('track_id');
}
public function tracks()
{
return $this->belongsToMany('Track', 'tag_track_user')->withPivot('user_id');
}
------------
// Track model
public function tags()
{
return $this->belongsToMany('Tag', 'tag_track_user')->withPivot('user_id');
}
public function users()
{
return $this->belongsToMany('User', 'tag_track_user')->withPivot('tag_id');
}
------------
// User model
public function tags()
{
return $this->belongsToMany('Tag', 'tag_track_user')->withPivot('track_id');
}
public function tracks()
{
return $this->belongsToMany('Track', 'tag_track_user')->withPivot('tag_id');
}
Now, with this setup you can get everything you want:
$user->tags->first()->users; // other users who used given tag
Tag::where('name','happy')->first()->tracks; // all tracks tagged 'happy'
$user->tracks()->where('title','Happy')->first()->tags; // all tags attached to song Happy
$user->tags->load('tracks')->fetch('tracks')->collapse(); // array of all the tracks related to all tags of a user (as arrays not models)
etc.
Of course the above will cause a few db queries, but that's normal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With