Laravel pivot 新增 load

jcc123發表於2018-07-07

有這樣的一個表結構

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 協議》,轉載必須註明作者和本文連結
NOT IS BECAUSE I WANT TO WRITE, BUT I WANT TO INCREASE, SO I GO TO WRITE~~

相關文章