Consider this simple many-to-many relationship in Laravel:
class User extends Eloquent {
public function roles()
{
return $this->belongsToMany('Role');
}
}
and
class Role extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
}
This is ok with schema of role_user
that keeps user_id
and role_id
. But what we if have some other constraints? For example in an app like Github, user is admin in repository A and is regular user in repository B. So we add repository_id
to role_user
table, but when I want to query user->roles
I want to look for that in current repository, that I keep reference of current_repository_id
in session. What changes should I do in models to do that?
Note: I don't want to change anything in using-code! Isn't anyway to put filter logic in model declaration? Because I'm at the middle of big project and it's tough to change every usage. Is it possible?
//User model
public function roles()
{
$repoID = MyApp::currentRepoID();
return $this->belongsToMany('Role', 'pivot_table_name', 'user_id', 'role_id')
->wherePivot('repository_id', $repoID);
}
If you need to add additional fields to the pivot table, you should use ->withPivot() method. If your pivot table structure is like:
id | role_id | user_id | repository_id
you should use
return $this->belongsToMany('Role', 'pivot_table_name', 'user_id', 'role_id')->withPivot('repository_id');
Then, wherever you use it, you have to do:
$role = Role::find(1);
$role->pivot->repository_id;
or
$user = User::find(1);
foreach ($user->roles as $role) {
echo $role->pivot->repository_id;
}
Check out Eloquent Triple Pivot (also on Packagist), it sounds like it does exactly what you want.
You'd set up your Models as User
, Repository
and Role
(a User
has many Repository
s and can have a Role
in each). Then look at the docs on the Github page (particularly step 6), and you'd define this on your Repository
model:
class Repository extends Eloquent {
...
public function getRolesAttribute() {
return $this->getThirdAttribute();
}
}
Then you can simply call
$user = User::find(1);
$repo = $user->repositories->first();
// or
$repo = $user->repositories->find(73);
$roles = $repo->roles;
// Or the above can be condensed into just...
$roles = User::findOrFail( 1 )
->repositories()
->findOrFail( 73 )
->roles;