Laravel:为多对多关系添加约束


Laravel: add constraint on many-to-many relationships

考虑Laravel:中的这种简单的多对多关系

class User extends Eloquent {
    public function roles()
    {
        return $this->belongsToMany('Role');
    }
}

class Role extends Eloquent {
    public function users()
    {
        return $this->belongsToMany('User');
    }
}

这对于保持user_idrole_idrole_user的模式是可以的。但是,如果我们有其他的限制呢?例如,在像Github这样的应用程序中,用户在存储库A中是管理员,在存储库B中是普通用户。因此,我们将repository_id添加到role_user表中,但当我想查询user->roles时,我想在当前存储库中查找它,我在会话中保留current_repository_id的引用。要做到这一点,我应该对模型做哪些更改?


注意:我不想在使用代码时更改任何内容!难道不应该把过滤逻辑放在模型声明中吗?因为我正处于一个大项目的中间,很难改变每一种用法。有可能吗?

//User model 
public function roles()
{
    $repoID = MyApp::currentRepoID();
    return $this->belongsToMany('Role', 'pivot_table_name', 'user_id', 'role_id')
        ->wherePivot('repository_id', $repoID);
}

如果需要向数据透视表添加其他字段,则应使用->withPivot()方法。如果您的数据透视表结构如下:

id | role_id | user_id | repository_id

你应该使用

return $this->belongsToMany('Role', 'pivot_table_name', 'user_id', 'role_id')->withPivot('repository_id');

然后,无论你在哪里使用它,你都必须这样做:

$role = Role::find(1);
$role->pivot->repository_id;

$user = User::find(1);
foreach ($user->roles as $role) {
    echo $role->pivot->repository_id;
}

看看Eloquent Triple Pivot(也在Packagist上),它听起来正是你想要的。

您可以将模型设置为UserRepositoryRole(一个User有许多Repository,每个Role都可以)。然后查看Github页面上的文档(特别是步骤6),您可以在Repository模型上定义它:

class Repository extends Eloquent {
    ...
    public function getRolesAttribute() {
        return $this->getThirdAttribute();
    }
}

然后你可以简单地调用

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