Laravel - Создание отношений HasManyThrough предоставляет уникальную коллекцию - PullRequest
0 голосов
/ 09 ноября 2018

У меня проблема с тем, чтобы заставить работать 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 возвращает несколько результатов, моя результирующая коллекция контейнеров доставки содержит повторяющиеся записи.Если бы я мог как-то поместить группу / уникальную в запрос промежуточной таблицы, то это было бы решено.

Я мог бы получить коллекцию с правильной загрузкой 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?

Структура таблицы

delivery_exceptions (где возникает эта связь)

  • product_id
  • delivery_id

delivery_containers

  • id
  • delivery_id

stock_movements

  • entity_id (связан с идентификатором поставки)
  • product_id

Отношения

  • A исключение доставки принадлежит продукту
  • A продукт hasMany stock_movements
  • A движение на складе принадлежит контейнер доставки
  • A исключение доставки hasMany контейнеры доставки ... (косвенно, через комбинацию движения товара и запаса)

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

Принятый ответ гораздо элегантнее, но это еще один способ сделать это:

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();
}
0 голосов
/ 10 ноября 2018

У вас там действительно жесткие настройки, и я не совсем уверен, что у меня есть полная идея (также из-за того, что вы использовали entity_id в каком-то месте вместо delivery_id). Но, тем не менее, я дал ему шанс.

Определенные вами отношения hasManyThrough на самом деле выглядят неплохо, но, на мой взгляд, есть лучший способ достичь результата. Но сначала давайте посмотрим на ваши отношения:

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

Поскольку StockMovement уже принадлежит DeliveryContainer, который в свою очередь принадлежит Delivery, отношение от StockMovement до Delivery (помеченное как 1) мне кажется устаревшим. В любом случае, чтобы получить отношение 2 в вашей модели, вы можете использовать пути 3 и 4 в своих интересах:

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

Очевидно, это даст вам все DeliveryContainers, не отфильтрованные Product. Поэтому я предлагаю добавить вторую функцию:

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