Laravel技巧之Pivot

今天使用了联表查询,发现数据中一种是attributes,一种是original,其中部分数据带pivot前缀,想调用带pivot的数据,使用$role->pivot->created_at;


参考文章:

https://leo108.com/pid-2263/


在关系式数据库中,要定义一个符合范式的多对多表关系需要一个中间表作为两个表的关系。在Laravel中这个表称为pivot,在查询出关联的记录之后,可以通过pivot属性来访问关联表的字段:

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

在实际应用中,这个中间表可能不仅仅包含两个表的外键,还有一些附加的字段,举个例子:

一个用户可以属于多个部门,即用户和部门是多对多关系,一个用户在不同部门里角色可能不一样,即用户和角色也是多对多。这个中间表的结构如下:

+---------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | user_id | int(10) unsigned | NO | | NULL | | | role_id | int(10) unsigned | NO | | NULL | | | department_id | int(10) unsigned | NO | | NULL | | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | +---------------+------------------+------+-----+---------+----------------+

获取一个用户在所有部门所对应的角色时:

foreach($user->departments as $department) { $role = Role::find($department->privot->role_id); }

可以看到步骤还是比较繁琐,如果这个pivot能像别的Model那样直接通过$department->privot->role来拿到角色信息就会方便很多。

研究了一下Laravel的代码,发现是可以实现的,首先新建一个类

namespace App\PivotModels; use Illuminate\Database\Eloquent\Relations\Pivot; use App\Models\Role; use App\Models\Department; class UserRole extends Pivot { public function role() { return $this->belongsTo(Role::class); } public function department() { return $this->belongsTo(Department::class); } }

然后在App\Models\Department类中重写newPivot方法:

public function newPivot(Model $parent, array $attributes, $table, $exists) { if ($parent instanceof User) { return new UserRole($parent, $attributes, $table, $exists); } return parent::newPivot($parent, $attributes, $table, $exists); }

修改App\Models\User类中的departments方法:

public function departments() { return $this->belongsToMany(Department::class, 'user_role', 'department_id', 'user_id') ->withPivot(['department_id', 'user_id', 'role_id']) // 这行要把中间表的字段都加上 ->withTimestamps(); }

这个时候在tinker中可以测试一下

$pivot = $user->departments()->first()->pivot; //输出一个App\PivotModels\UserRole对象 $pivot->role; // 输出对应的角色对象 $pivot->department; // 输出对应的部门

更进一步,Illuminate\Database\Eloquent\Relations\Pivot这个类实际上是继承于Illuminate\Database\Eloquent\Model类的,也就是说可以通过mutators功能来自定义getter/setter。(经测试pivot不支持model中的$appends/$with等属性,定义了也不会有相应的行为,但仍可以通过load方法来加载关联对象)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值