Laravel - 使 HasManyThrough 关系提供唯一集合

Laravel - Making a HasManyThrough Relationship provide a unique collection

我在使用 hasManyThrough 时遇到问题:

public function deliveryContainers() : HasManyThrough
{
    return $this->hasManyThrough(
        DeliveryContainer::class, // Final
        StockMovement::class, // Intermediate
        'product_id', // Foreign key on Intermediate
        'id', // Foreign key on Final
        'product_id', // Local key on Current
        'location_id' // Local key on Intermediate
    )->where('delivery_id', $this->delivery_id);
}

由于 stockMovements table returns 多个结果,我生成的交付容器集合包含重复条目。如果我能以某种方式在中间 table 查询上放置 group/unique 那么这将得到解决。

我可以使用以下方法获取带有正确的 deliveryContainers 急切加载的集合:

public function deliveryContainers()
{
    return $this->hasMany(StockMovement::class, 'entity_id', 'delivery_id')
        ->with('deliveryContainer')
        ->where('product_id', $this->product_id)
        ->get()
        ->unique('location_id');
}

但是,要访问 deliveryContainer,我现在有以下内容:

foreach($this->deliveryContainers() as $row){
    $row->deliveryContainer->id;    
}

以及我想要的...

foreach($this->deliveryContainers() as $row){
    $row->id;
}

有什么方法可以将预加载关系提升一个级别(如果可以用它来描述的话),或者甚至更好地向 hasManyThrough 关系添加某种独特的过滤器?

Table结构

delivery_exceptions(此关系的来源)

delivery_containers

stock_movements

关系

你那里的设置真的很难,我不完全确定我是否理解了它背后的全部想法(也是因为你在某些地方使用 entity_id 而不是 delivery_id ).尽管如此,我还是试了一下。

您定义的 hasManyThrough 关系实际上看起来还不错,但我认为有更好的方法可以得到结果。但首先让我们看看你们的关系:

                                               3
                            +-------------------------------------+
               4            v                                     |
        +-------------> Delivery <----------+                     |
        |                                   | 1                   |
        +                                   +                     +
DeliveryException +---> Product <---+ StockMovement +---> DeliveryContainer
        +                                                         ^
        +---------------------------------------------------------+
                                      2

因为StockMovement已经属于DeliveryContainer,而在return中属于Delivery,从StockMovement到[=18的关系=](标记为 1)对我来说似乎已经过时了。无论如何,要在你的模型上获得关系 2,你可以使用路径 34 来发挥你的优势:

class DeliveryException
{
    public function deliveryContainers(): HasMany
    {
        return $this->hasMany(DeliveryContainer::class, 'delivery_id', 'delivery_id');
    }
}

显然,这将为您提供未被 Product 过滤的所有 DeliveryContainers。因此我建议添加第二个函数:

public function deliveryContainersByProduct(): HasMany
{
    return $this->deliveryContainers()
        ->whereHas('stockMovements', function ($query) {
             $query->where('product_id', $this->product_id);
        });
}

接受的答案要优雅得多,但这也是另一种方法:

public function deliveryContainers1()
{
    return $this->hasManyThrough(
        DeliveryContainer::class, // Final
        StockMovement::class, // Intermediate
        'product_id', // Foreign key on Intermediate
        'id', // Foreign key on Final
        'product_id', // Local key on Current
        'location_id' // Local key on Intermediate
    )
        ->where('delivery_id', $this->delivery_id)
        ->distinct();
}