自定义 Laravel 关系?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39213022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom Laravel Relations?
提问by Johnny
Hypothetical situation: Let's say we have 3 models:
假设情况:假设我们有 3 个模型:
User
Role
Permission
User
Role
Permission
Let's also say User
has a many-to-many relation with Role
, and Role
has a many-to-many relation with Permission
.
假设与具有User
多对多关系Role
,并且与Role
具有多对多关系Permission
。
So their models might look something like this. (I kept them brief on purpose.)
所以他们的模型可能看起来像这样。(我故意让它们简短。)
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);
}
}
What if you wanted to get all the Permission
s for a User
?There isn't a BelongsToManyThrough
.
如果您想获得 a 的所有Permission
sUser
怎么办?没有一个BelongsToManyThrough
。
It seems as though you are sort of stuck doing something that doesn't feel quite right and doesn't work with things like User::with('permissions')
or User::has('permissions')
.
似乎您在做一些感觉不太正确并且不适用于诸如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;
}
}
This example is, just one example, don't read too much into it. The point is, how can you define a customrelationship? Another example could be the relationship between a facebook comment and the author's mother. Weird, I know, but hopefully you get the idea. Custom Relationships. How?
这个例子只是一个例子,不要过多阅读。关键是,如何定义自定义关系?另一个例子可能是 facebook 评论和作者的母亲之间的关系。奇怪,我知道,但希望你能明白。自定义关系。如何?
In my mind, a good solution would be for that relationship to be described in a similar way to how describe any other relationship in Laravel. Something that returns an Eloquent Relation
.
在我看来,一个好的解决方案是用类似于 Laravel 中描述任何其他关系的方式来描述这种关系。返回 Eloquent 的东西Relation
。
class User
{
public function permissions() {
return $this->customRelation(Permission::class, ...);
}
}
Does something like this already exist?
像这样的东西已经存在了吗?
回答by Johnny
The closest thing to a solution was what @biship posted in the comments. Where you would manually modify the properties of an existing Relation
. This might work well in some scenarios. Really, it may be the right solution in some cases. However, I found I was having to strip down all of the constraints
added by the Relation
and manually add any new constraints
I needed.
最接近解决方案的是@biship在评论中发布的内容。您将在哪里手动修改现有Relation
. 这在某些情况下可能很有效。确实,在某些情况下它可能是正确的解决方案。但是,我发现我不得不删除所有constraints
添加的内容Relation
并手动添加constraints
我需要的任何新内容。
My thinking is this... If you're going to be stripping down the constraints
each time so that the Relation
is just "bare". Why not make a custom Relation
that doesn't add any constraints
itself and takes a Closure
to help facilitate adding constraints
?
我的想法是......如果你constraints
每次都要剥离,以便它Relation
只是“裸露”。为什么不制作一个Relation
不添加任何内容constraints
并需要一个Closure
帮助促进添加的自定义constraints
?
Solution
解决方案
Something like this seems to be working well for me. At least, this is the basic concept:
像这样的事情对我来说似乎很有效。至少,这是基本概念:
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();
}
}
The methods not implemented yet are used for eager loading and must be declared as they are abstract. I haven't that far yet. :)
尚未实现的方法用于预先加载并且必须声明为抽象方法。我还没有那么远。:)
And a trait to make this new Custom
Relation easier to use.
以及使这个新Custom
Relation 更易于使用的特性。
trait HasCustomRelations
{
public function custom($related, Closure $baseConstraints)
{
$instance = new $related;
$query = $instance->newQuery();
return new Custom($query, $this, $baseConstraints);
}
}
Usage
用法
// 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.
Github
GitHub
I went a ahead and put all this on Githubjust in case there are more people who are interested in something like this. This is still sort of a science experiment in my opinion. But, hey, we can figure this out together. :)
我继续前进并将所有这些都放在 Github上,以防有更多人对这样的事情感兴趣。在我看来,这仍然是一种科学实验。但是,嘿,我们可以一起解决这个问题。:)
回答by choy vallejo
I believe this concept already exists. You may choose on using Laravel ACL Roles and Permissions or Gate, or a package known as Entrust by zizaco.
我相信这个概念已经存在。你可以选择使用 Laravel ACL Roles and Permissions 或 Gate,或者一个名为 Entrust by zizaco 的包。
Laracast - watch video 13 and 14
Good luck!
祝你好运!
回答by pseudoanime
Have you looked into the hasManyThrough
relationship that Laravel offers?
你有没有研究过hasManyThrough
Laravel 提供的关系?
It should help you retrieve all the permissions for a user.
它应该可以帮助您检索用户的所有权限。