audunru/eager-load-pivot-relations

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

v3.0.1 2024-05-25 06:51 UTC

README

Build Status Coverage Status StyleCI

注意:这是一个基于 ajcastro/eager-load-pivot-relations 的分支,支持 Laravel 8 及以上版本,也由 ajcastro 编码。感谢原作者为这个包及其工作所做的贡献。

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

安装

composer require audunru/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 audunru\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 audunru\EagerLoadPivotRelations\EagerLoadPivotTrait;
class Plan extends \Eloquent
{
    use EagerLoadPivotTrait;
}

因此,我们不必使用 pivot,而可以通过定义的枢纽访问器 planItem 预加载它。

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