Laravel pivot 添加 load
25

有这样的一个表结构

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

NOT IS BECAUSE I WANT TO WRITE,
BUT I WANT TO INCREASE,
SO I GO TO WRITE~~

本帖由系统于 3个月前 自动加精
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!