Laravel:在多对多关系上添加约束

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 Repositorys 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;