Joh*_*nny 8 php laravel eloquent
假设情况:假设我们有3个型号:
UserRolePermission我们也要说它User与多对多关系Role,并且Role具有多对多的关系Permission.
所以他们的模型可能看起来像这样.(我故意将它们简要说明.)
class User
{
public function roles() {
return $this->belongsToMany(Role::class);
}
}
class Role
{
public function users() {
return $this->belongsToMany(User::class);
}
public function permissions() {
return $this->belongsToMany(Permission::class);
}
}
class Permission
{
public function roles() {
return $this->belongsToMany(Role::class);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想得到所有的Permissions User怎么办?没有BelongsToManyThrough.
看起来好像你做了一些感觉不太合适的东西并且不适用于User::with('permissions')或类似的东西User::has('permissions').
class User
{
public function permissions() {
$permissions = [];
foreach ($this->roles as $role) {
foreach ($role->permissions as $permission) {
$permissions = array_merge($permissions, $permission);
}
}
return $permissions;
}
}
Run Code Online (Sandbox Code Playgroud)
这个例子只是一个例子,不要读太多.关键是,您如何定义自定义关系?另一个例子可能是Facebook评论和作者母亲之间的关系.很奇怪,我知道,但希望你明白了.自定义关系.怎么样?
在我看来,一个很好的解决方案就是以类似于描述Laravel中任何其他关系的方式来描述这种关系.返回Eloquent的东西Relation.
class User
{
public function permissions() {
return $this->customRelation(Permission::class, ...);
}
}
Run Code Online (Sandbox Code Playgroud)
这样的事情已经存在吗?
Joh*_*nny 10
最接近解决方案的是@biship 在评论中发布的内容.您将手动修改现有属性的位置Relation.这在某些情况下可能效果很好.实际上,在某些情况下,它可能是正确的解决方案.但是,我发现我不得不删除所有constraints添加的Relation并手动添加constraints我需要的任何新内容.
我的想法就是这样......如果你constraints每次都要剥离,那么这Relation只是"光秃秃的".为什么不制作一个Relation不添加任何东西的自定义constraints并且需要Closure帮助促进添加constraints?
这样的事情对我来说似乎很有效.至少,这是基本概念:
class Custom extends Relation
{
protected $baseConstraints;
public function __construct(Builder $query, Model $parent, Closure $baseConstraints)
{
$this->baseConstraints = $baseConstraints;
parent::__construct($query, $parent);
}
public function addConstraints()
{
call_user_func($this->baseConstraints, $this);
}
public function addEagerConstraints(array $models)
{
// not implemented yet
}
public function initRelation(array $models, $relation)
{
// not implemented yet
}
public function match(array $models, Collection $results, $relation)
{
// not implemented yet
}
public function getResults()
{
return $this->get();
}
}
Run Code Online (Sandbox Code Playgroud)
尚未实现的方法用于预先加载,必须声明它们是抽象的.我还没那么远.:)
并且使这个新Custom关系更容易使用的特性.
trait HasCustomRelations
{
public function custom($related, Closure $baseConstraints)
{
$instance = new $related;
$query = $instance->newQuery();
return new Custom($query, $this, $baseConstraints);
}
}
Run Code Online (Sandbox Code Playgroud)
// app/User.php
class User
{
use HasCustomRelations;
public function permissions()
{
return $this->custom(Permission::class, function ($relation) {
$relation->getQuery()
// join the pivot table for permission and roles
->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id')
// join the pivot table for users and roles
->join('role_user', 'role_user.role_id', '=', 'permission_role.role_id')
// for this user
->where('role_user.user_id', $this->id);
});
}
}
// app/Permission.php
class Permission
{
use HasCustomRelations;
public function users()
{
return $this->custom(User::class, function ($relation) {
$relation->getQuery()
// join the pivot table for users and roles
->join('role_user', 'role_user.user_id', '=', 'users.id')
// join the pivot table for permission and roles
->join('permission_role', 'permission_role.role_id', '=', 'role_user.role_id')
// for this permission
->where('permission_role.permission_id', $this->id);
});
}
}
You could now do all the normal stuff for relations without having to query in-between relations first.
Run Code Online (Sandbox Code Playgroud)
我前进了一下,把所有这些都放在Github上以防万一有更多人对这样的事感兴趣.在我看来,这仍然是一种科学实验.但是,嘿,我们可以一起解决这个问题.:)