ajcastro/eager-load-pivot-relations

为 Laravel Eloquent 的 BelongsToMany 关系预先加载枢轴关系。

v0.3.0 2022-11-02 13:31 UTC

This package is auto-updated.

Last update: 2024-08-30 01:23:20 UTC


README

为 Laravel Eloquent 的 BelongsToMany 关系预先加载枢轴关系。
Medium 故事: https://medium.com/@ajcastro29/laravel-eloquent-eager-load-pivot-relations-dba579f3fd3a

安装

composer require ajcastro/eager-load-pivot-relations

使用示例

在某些情况下,枢轴模型有需要预先加载的关系。例如,在一个采购系统中,我们有以下

表格

items
 - id
 - name
units
 - id
 - name (pc, box, etc...)
plans (annual procurement plan)
 - id
plan_item (pivot for plans and items)
 - id
 - plan_id
 - item_id
 - unit_id

模型

class Unit extends \Eloquent {
}
use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;
class Item extends \Eloquent
{
    // Use the trait here to override eloquent builder.
    // It is used in this model because it is the relation model defined in
    // Plan::items() relation.
    use EagerLoadPivotTrait;
    public function plans()
    {
        return $this->belongsToMany('Plan', 'plan_item');
    }
}
class Plan extends \Eloquent
{
    public function items()
    {
        return $this->belongsToMany('Item', 'plan_item')
            ->using('PlanItem')
            // make sure to include the necessary foreign key in this case the `unit_id`
            ->withPivot('unit_id', 'qty', 'price');
    }
}
// Pivot model
class PlanItem extends \Illuminate\Database\Eloquent\Relations\Pivot
{
    protected $table = 'plan_item';
    public function unit()
    {
        return $this->belongsTo('Unit');
    }
}

从上面的代码中,plansitems多对多 关系。计划中的每个项目都有一个选定的 unit,即计量单位。枢轴模型也可能有其他多对多关系。

预先加载枢轴关系

在预先加载枢轴模型时使用关键字 pivot。因此,从上面的例子中,枢轴模型 PlanItem 可以通过这样做来预先加载 unit 关系

return Plan::with('items.pivot.unit')->get();

结果数据结构将是

image

您还可以访问其他关系,例如

return Plan::with([
  'items.pivot.unit',
  'items.pivot.unit.someRelation',
  'items.pivot.anotherRelation',
  // It is also possible to eager load nested pivot models
  'items.pivot.unit.someBelongsToManyRelation.pivot.anotherRelationFromAnotherPivot',
])->get();

自定义枢轴访问器

您可以根据需要自定义 "枢轴访问器",因此我们不必使用关键字 pivot,我们可以将其声明为 planItem。只需在 BelongsToMany 关系的定义中链式调用 as() 方法。

class Plan extends \Eloquent
{
    public function items()
    {
        return $this->belongsToMany('Item', 'plan_item')
            ->withPivot('unit_id', 'qty', 'price')
            ->using('PlanItem')
            ->as('planItem');
    }
}

确保我们还在主要模型(即 Plan 模型)上使用特性,因为该包需要访问 belongsToMany 关系(items 关系)以识别使用的枢轴访问器。

use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;
class Plan extends \Eloquent
{
    use EagerLoadPivotTrait;
}

因此,我们可以使用定义的枢轴访问器 planItem 来预先加载它,而不是使用 pivot

return Plan::with('items.planItem.unit')->get();
$plan = Plan::with('items.planItem.unit');
foreach ($plan->items as $item) {
    $unit = $item->planItem->unit;
    echo $unit->name;
}

其他示例和用例

https://github.com/ajcastro/eager-load-pivot-relations-examples