自定义拉拉维尔关系?

2022-08-30 22:19:03

假设情况:假设我们有3个模型:

  • User
  • Role
  • Permission

我们还假设 与 具有多对多关系,并且 与 具有多对多关系。UserRoleRolePermission

所以他们的模型可能看起来像这样。(我故意让它们保持简短。

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

如果您想获得用户的所有权限该怎么办没有 .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;
    }
}

这个例子,只是一个例子,不要读太多。关键是,如何定义自定义关系?另一个例子可能是Facebook评论与作者母亲之间的关系。很奇怪,我知道,但希望你明白了。自定义关系。如何?

在我看来,一个好的解决方案是用类似于描述Laravel中任何其他关系的方式来描述这种关系。返回雄辩的东西。Relation

class User
{
    public function permissions() {
        return $this->customRelation(Permission::class, ...);
    }
}

这样的事情已经存在了吗?


答案 1

最接近解决方案的是@biship评论中发布的内容。手动修改现有 .这在某些情况下可能很有效。实际上,在某些情况下,这可能是正确的解决方案。但是,我发现我必须删除所有添加的内容,并手动添加我需要的任何新内容。RelationconstraintsRelationconstraints

我的想法是这样的...如果你要剥离每次,以便只是“裸露”。为什么不做一个不添加任何本身的自定义,并采取一个来帮助促进添加?constraintsRelationRelationconstraintsClosureconstraints

溶液

像这样的东西对我来说似乎很有效。至少,这是基本概念:

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

尚未实现的方法用于预先加载,并且必须声明为抽象方法。我还没有那么远。:)

以及使这种新关系更易于使用的特征。Custom

trait HasCustomRelations
{
    public function custom($related, Closure $baseConstraints)
    {
        $instance = new $related;
        $query = $instance->newQuery();

        return new Custom($query, $this, $baseConstraints);
    }
}

用法

// 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上,以防万一有更多的人对这样的东西感兴趣。在我看来,这仍然是一个科学实验。但是,嘿,我们可以一起解决这个问题。:)


答案 2

你有没有研究过Laravel提供的关系?hasManyThrough

Laravel HasManyThrough

它应该可以帮助您检索用户的所有权限。


推荐