首页 > 解决方案 > 基于父级的 Laravel 急切加载约束

问题描述

我不知道我正在尝试的事情是否可行,但感觉应该是这样。我将首先概述设置,然后概述我遇到的问题。我有以下表格(为本示例简化):

Schema::create('groups', function (Blueprint $table) {
    $table->id();
    $table->string('slug');
    $table->string('entity_type')->index();
    $table->timestamps();
});

Schema::create('fields', function (Blueprint $table) {
    $table->id();
    $table->string('slug');
    $table->unsignedBigInteger('dynamic_model_id')->nullable();
    $table->timestamps();

    $table->foreign('group_id')
        ->references('id')
        ->on('groups');
});

Schema::create('group_instances', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('group_id');
    $table->morphs('entity');
    $table->timestamps();

    $table->foreign('group_id')
        ->references('id')
        ->on('groups')
        ->onUpdate('cascade')
        ->onDelete('cascade');
});

Schema::create('values', function (Blueprint $table) {
    $table->id();
    $table->text('content')->nullable();
    $table->unsignedBigInteger('field_id');
    $table->unsignedBigInteger('group_instance_id');
    $table->timestamps();

    $table->foreign('field_id')
        ->references('id')
        ->on('fields')
        ->onUpdate('cascade')
        ->onDelete('cascade');

    $table->foreign('group_instance_id')
        ->references('id')
        ->on('group_instances')
        ->onUpdate('cascade')
        ->onDelete('cascade');
});

上述每个表都有一个相应的模型,我在其中定义了它们的关系:

// Group.php
public function fields()
{
    return $this->hasMany(Field::class, 'group_id');
}

public function groupInstances()
{
    return $this->hasMany(GroupInstance::class, 'group_id');
}
// Field.php
public function group()
{
    return $this->belongsTo(Group::class, 'group_id');
}

public function values()
{
    return $this->hasMany(Value::class, 'field_id');
}
// GroupInstance.php
public function group()
{
    return $this->belongsTo(Group::class, 'group_id');
}

public function values()
{
    return $this->hasMany(Value::class, 'group_instance_id');
}

public function entity()
{
    return $this->morphTo();
}
// Value.php
public function field()
{
    return $this->belongsTo(Field::class);
}

public function groupInstance()
{
    return $this->belongsTo(GroupInstance::class);
}

我正在尝试构建修改后的 EAV 以允许灵活的数据结构。暂时搁置 EAV 模式的优缺点,此实现Fields用作单个数据项的定义,并将Groups这些字段组织到逻辑桶中。例如,用户个人资料将是组,而他们的姓名、电子邮件等将是字段。

因此,如果Fields&Groups是模式,GroupInstances并且Values将是数据。GroupInstances表示 a 的一个实例Group。每个都GroupInstance将具有对this对应Values的每个Field定义的内容的引用。因此,在作为用户个人资料和姓名的示例中,电子邮件等是多个连接的,然后一个连接的将是实际数据,如“John Doe”、“john@email.com”等。GroupGroupInstanceGroupFieldsGroupInstanceValues

所以想法是所有用户共享在groupsfields表中定义的相同灵活模式。然而,他们每个人都有自己的group_instancesvalues正如人们所期望的那样。

问题:)

使用模型groups上定义的关系,我User想为一组用户预先加载所有记录(例如)。但是,' 需要仅限于属于该特定用户的那些。GroupGroupInstancegroups.groupInstancesGroupInstance

注意:这个系统被设置为多态的,动态模式/数据可以附加到应用程序中的各种模型,但是为了这个问题的目的,我将使用User模型作为我们的实体。

// User.php
public function getEntityTypeAttribute()
{
    return static::class;
}
    
public function groups()
{
    return $this->hasMany(Group::class, 'entity_type', 'entity_type');
}

像这样使用上述关系:

User::with(['groups.groupInstances'])->get();

这会GroupInstances为系统中的所有用户加载,而不仅仅是GroupInstances与特定用户相关的。但是,您可以使用急切加载约束在单个用户上获得所需的结果,因为 users :

$user = User::first();
$user->load(['groups.groupInstances' => function($query) use ($user) {
    $query->where('group_instances.entity_id', '=', $user->id);
    $query->where('group_instances.entity_type', '=', $user->entity_type);
}]);

这就是我卡住的地方。我不知道如何将相同的急切约束应用于您获得多个用户的查询,以便您只获得属于该特定用户的组实例记录。考虑到表格的设置,我不知道这是否可能,但我很想听听有关自定义关系、急切约束或表格重组的想法,以实现我上面概述的内容。预先感谢您对这个问题的任何启发。

标签: laraveleloquentconstraintsrelationship

解决方案


推荐阅读