I asked this on the discord the other day, but since we're way off-topic from that original post, I've decided to come here for some additional guidance. Can't include links yet, but can provide if necessary.
To sum up my original issues: 1) I was using composite primary keys 2) I was calling to the pivot table quite a lot a la EventUsers::where()...
Based on the advice I received there, I'm trying to remedy this. I have 3 tables in my app, that represent the roles a user plays in an event. Here's how I've set this up:
event
- id
- name
- location
user
- id
- name
- email
role
- id
- role
user_event_roles
- id
- user_id
- event_id
- role_id
First of all, does this make sense? I was told in the other thread that I should keep the ID around in the pivot table, but I'm also reading quite often that it's unnecessary.
And for the models:
event:
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class, 'user_event_roles')->withPivot('role_id')->withTimestamps();
}
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class, 'user_event_roles')->withPivot('user_id');
}
user:
public function events(): BelongsToMany
{
return $this->belongsToMany(Season::class, 'user_event_roles')->withPivot('role_id')->withTimestamps();
}
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class, 'user_event_roles');
}
role:
public function events(): BelongsToMany
{
return $this->belongsToMany(Season::class, 'user_event_roles')->withPivot('user_id')->withTimestamps();
}
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class, 'user_event_roles');
}
Now, as I start implementing my functions, I'm increasingly wondering if I'm doing this correctly, so I'd appreciate the insight on what the best practice or the "right" way of utilizing this setup is.
Here are the tasks, that I'm trying to accomplish:
Attach with the role string:
$user->events()->attach([$event_id => ['role_id' => Role::where('role', $roleString)->first()->id]])
Is there a more direct way than retrieving the id first and then writing it?
Get a specific user's role in a specific event:
$eventUserRole = $event->users()->where('users.id', $user->id)
->join('roles', 'user_event_roles.role_id', '=', 'roles.id')
->select('users.*', 'roles.role')
->first()->role;
Seems a bit convoluted to ask: I have an event, I have a user, what role do they play?
Get all users in an event along with their role:
$event_users = User::join('user_event_roles', 'users.id', '=', 'user_event_roles.user_id')
->join('roles', 'user_event_roles.role_id', '=', 'roles.id')
->where('user_event_roles.season_id', $id)
->select('users.*', 'roles.role')
->get();
Again, seems like a lot. Previously I tried this, but it returns all roles for the user, not just the ones for this event. It gave me the user and then an array of roles instead of a user with role for each user/role combination.
$event_users = $event->users()
->with(['roles' => function ($query) {
$query->select('role');
}])
->select('users.id', 'users.first_name', 'users.last_name', 'users.email')
->groupBy('users.id', 'users.first_name', 'users.last_name')
->get();
How can I improve any of these?
Also, is there a way of attaching a whole list of users with the same role to an event, e.g. my entire morning shift? I mean, I could foreach over them, but I'm wondering.
I'm also beginning to suspect I would have been better off just using a string for the role instead of referencing it from another table. That way I wouldn't have to join it every time.
Thanks in advance for any pointers!