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\ModelsetRelation方法。

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

测试示例可以直观的看下

file
最后模型整理

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 协议》,转载必须注明作者和本文链接
Make everything simple instead of making difficulties as simple as possible
本帖由系统于 6年前 自动加精
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!