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

  • User
  • Role
  • Permission

也就是说UserRole有多对多关系,RolePermission有多对多关系.

所以他们的模型可能看起来像这样.(我故意让他们简短.)

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 100s for a 101?没有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;
    }
}

这个例子只是一个例子,不要读太多.关键是,你如何定义一个custom人的关系?另一个例子可能是facebook comments 与作者母亲之间的关系.奇怪,我知道,但希望你能明白.自定义关系.怎样

在我看来,一个很好的解决方案是,用类似于描述拉威尔中任何其他关系的方式来描述这种关系.返回一个Eloquent 的Relation.

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

Does something like this already exist?

推荐答案

最接近解决方案的是@biship posted in the comments.您可以手动修改现有数据库的属性.在某些情况下,这可能很有效.的确,在某些情况下,这可能是正确的解决方案.然而,我发现我必须go 掉Relation添加的所有constraints,并手动添加我需要的任何新constraints.

我的 idea 是...如果你每次都要go 掉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();
    }
}

尚未实现的方法用于即时加载,必须以抽象的形式声明.我还没到那一步.:)

这是一个让这个新的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

我先取了all this on github,以防有更多的人对这样的东西感兴趣.在我看来,这仍然是一种科学实验.但是,嘿,我们可以一起解决这个问题.:)

Laravel相关问答推荐

Laravel 10 - 没有 $append 属性的Eloquent 的热切加载

Dompdf 古吉拉特语和印地语文本未正确显示

V-icon 在 Vuetify 3 中不显示图标

Laravel 获取具有多对多关系的中间表数据

导出所有客户端不起作用,文件保存时没有名称和扩展名

在 Laravel 中设置多个 Vue 组件的问题

Laravel 5.2 无法打开 laravel.log

自定义 Laravel 关系?

在 laravel 5 中的表单请求验证后传递旧输入

使用 Eloquent 的 Laravel 块方法

如何在 laravel 中安装 PHPExcel 库?

Laravel Auth::attempt() 返回 false

如何在 Laravel 5.5 中扩展 vendor 包服务提供者

413请求实体在laravel homestead for windows中太大的nginx服务器

在 Laravel 5 中找不到类App\Http\Controllers\Artisan

Eloquent - 更新集合中的所有模型

Laravel 全部返回 ID 变为 0

防止 Eloquent 查询上的模型水合

使用 Laravel 使用 2 个磁盘复制文件

使用 Carbon 将小时转换为 PM 和 AM