Laravel pivot 添加 load
有这样的一个表结构
tables
projects
- id
- name
roles
- id
- name
users
- id
- name
project_user
- project_id
- user_id
- role_id
Model
class Project extends BaseModel
{
public function users()
{
return $this->belongsToMany(User::class);
}
}
class Role extends Model
{
...
}
class User extends Model
{
public function projects()
{
return $this->belongsToMany(Project::class);
}
}
用户可以参加多个项目,是多对多的关系。
用户可以有多个角色,也是多对多的关系。
假如,要查询,用户在某个项目下的角色。
$user = user::find(1);
foreach ($user->projects as $project){
$role = Role::find($project->pivot->role_id);
};
有没有可能直接这样
$user = user::find(1);
foreach ($user->projects as $project){
$role = $project->pivot->role;
};
这需要自定义一个中间表模型,与角色关联
laravel5.5 已经支持自定义中间表模型 pivot。之前的版本也可以,只不过麻烦一点,可以参考Laravel 技巧之 Pivot。
use Illuminate\Database\Eloquent\Relations\Pivot;
class ProjectUserPivot extends Pivot
{
public function role()
{
return $this->belongsTo(Role::class);
}
}
使用中间表
这里要把role_id
带上。
class User extends Model
{
public function projects()
{
return $this->belongsToMany(Project::class)->using(ProjectUser::class)->withPivot('role_id');;
}
}
这样就可以优雅的通过中间表查找用户角色了。
这样操作在后台处理数据时没有问题,假如要把通过中间表获得的角色数据传到视图上进行展示或者通过api请求数据时,这样就不行了。
想着在中间表添加个这样的属性
use Illuminate\Database\Eloquent\Relations\Pivot;
class ProjectUserPivot extends Pivot
{
protected $with=['role'];
public function role()
{
return $this->belongsTo(Role::class);
}
}
测试的时候发现不支持with属性,幸好load支持,不然就只能嘎嘎了。
这样只能另想其它办法了。其实我们只要找到laravel什么时候把中间表的模型数据添加进去,然后在这时候为中间表模型添加一个load。
通过查看 belongsToMany
的方法,最后定位到为Illuminate\Database\Eloquent\Relations\BelongsToMany
的
protected function hydratePivotRelation(array $models)
{
// To hydrate the pivot relationship, we will just gather the pivot attributes
// and create a new Pivot model, which is basically a dynamic model that we
// will set the attributes, table, and connections on it so it will work.
foreach ($models as $model) {
$model->setRelation($this->accessor, $this->newExistingPivot(
$this->migratePivotAttributes($model)
));
}
}
可以看到这里调用了Illuminate\Database\Eloquent\Model
的setRelation
方法。
$model->setRelation($this->accessor, $this->newExistingPivot(
$this->migratePivotAttributes($model)
));
查看 setRelation
方法.在这个trait里面Illuminate\Database\Eloquent\Concerns\HasRelationships
/**
* Set the specific relationship in the model.
*
* @param string $relation
* @param mixed $value
* @return $this
*/
public function setRelation($relation, $value)
{
$this->relations[$relation] = $value;
return $this;
}
在 Project
模型里添加新的方法覆盖掉setRelation
class Project extends BaseModel
{
public function users()
{
return $this->belongsToMany(User::class);
}
public function setRelation($relation, $value)
{
if($value instanceof ProjectUserPivot){
$this->relations[$relation] =$value->load('role');
return $this;
}
return parent::setRelation($relation, $value);
}
}
测试示例可以直观的看下
最后模型整理
class Project extends BaseModel
{
public function users()
{
return $this->belongsToMany(User::class);
}
public function setRelation($relation, $value)
{
if($value instanceof ProjectUserPivot){
$this->relations[$relation] =$value->load('role');
return $this;
}
return parent::setRelation($relation, $value);
}
}
class Role extends Model
{
...
}
class User extends Model
{
public function projects()
{
return $this->belongsToMany(Project::class)->using(ProjectUser::class)->withPivot('role_id');;
}
}
use Illuminate\Database\Eloquent\Relations\Pivot;
class ProjectUserPivot extends Pivot
{
public function role()
{
return $this->belongsTo(Role::class);
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: