Laravel Eloquent — объединение двух результатов модели eloquent (не коллекций)

#php #laravel #eloquent #query-builder #laravel-query-builder

#php #laravel #eloquent #конструктор запросов #laravel-конструктор запросов

Вопрос:

У меня есть таблица движения запасов, которая показывает историю продукта (получение, перемещение местоположения и т. Д.)

У меня есть два запроса, которые вычисляют (через совокупные суммы):

  1. Исходное полученное кол-во.
  2. Текущее текущее количество (после того, как вещи были перемещены).

Оба этих запроса возвращают коллекцию одинаковых моделей. В каждом из них всегда будет одинаковое количество результатов, а идентификаторы product_id всегда будут одинаковыми. Единственная часть, которая отличается, — это полученное / текущее количество, и я хочу каким-то образом объединить отдельные записи в новую коллекцию. т.е.

Одна запись из запроса 1:

 0 => StockMovement {#1602 ▼
  #original: array:2 [▼
    "live_qty" => "8"
    "product_id" => "2606598e-4150-461a-9e91-10d67cce8daa"
  ]
}
 

Одна запись из запроса 2;

 0 => StockMovement {#1602 ▼
  #original: array:2 [▼
    "received_qty" => "15"
    "product_id" => "2606598e-4150-461a-9e91-10d67cce8daa"
  ]
}
 

Я пытаюсь получить объединенный результат, который выглядит следующим образом:

 0 => StockMovement {#1602 ▼
  #original: array:3 [▼
    "received_qty" => "15"
    "live_qty" => "8"
    "product_id" => "2606598e-4150-461a-9e91-10d67cce8daa"
  ]
}
 

Я хочу сделать это таким образом, чтобы не преобразовывать объект Product в массив, поскольку мне нужны отношения, которые встроены в него.

В настоящее время я взломал это следующим образом:

 $live = $this->liveQtyCollection();
$merged = $this->receivedQtyCollection()->map(function(StockMovement $received) use($live){
    $line = $live->where('product_id', $received->product_id)->first();
    return arrayToObject(array_merge($received->toArray(), $line->toArray()));
});
return $merged;
 

arrayToObject Функция рекурсивно преобразует массив обратно в объект, поэтому я могу использовать селектор стрелок так же, как когда это была его исходная коллекция, но я уверен, что должен быть лучший способ!

Я пробовал:

  • Слияние
  • Объединение
  • Все

Моя конечная цель — иметь возможность использовать полученную коллекцию следующим образом:

 @foreach($stockMovements as $stockMovement)
    {{ $stockMovement->id }}
    {{ $stockMovement->live_qty }}
    {{ $stockMovement->received_qty }}
@endforeach
 

Комментарии:

1. «Все наборы с несколькими результатами, возвращаемые Eloquent, являются экземплярами объекта Illuminate Database Eloquent Collection». Почему вы сказали «не коллекции»?

2. Я предполагаю, что я думаю о коллекции как о «коллекции результатов модели eloquent». Я хочу убедиться, что я не разбиваю модель stockMovement на массив или обычную коллекцию, т.Е. Я хочу сохранить все ее функциональные возможности, например, $stockMovement->product->title где stockMovement принадлежит продукту, через product_id

3. Я думаю, вы можете попробовать использовать этот способ: laravel.com/docs/5.8/eloquent-relationships

4. @loic.lopez спасибо. Я уже знаю, что такое отношения. Я просто пытаюсь объединить два вышеуказанных запроса, сохраняя при этом отношения нетронутыми. Если я преобразую в массив перед слиянием, то отношения будут потеряны.

Ответ №1:

Вы можете использовать этот код:

 $collection = collect();
$cars = Car::all();
$bikes = Bike::all();

foreach ($cars as $car)
    $collection->push($car);

foreach ($bikes as $bike)
    $collection->push($bike);
 

Источник

Ответ №2:

Я знаю, что вы упомянули в своем вопросе, что вы не имели в виду коллекции, а также что вы уже пытались объединить, но ради обсуждения я подумал, что добавлю свой ответ, поскольку это сработало именно для того, что мне было нужно; объединение ответов двух вызовов модели.

 $quote = AppAllQuotes::withoutGlobalScopes()->find($quote_id);
$settings = AppSettings::findOrFail(1);
$settings = collect($settings);
$quote = collect($quote);
$merged = $quote->merge($settings);

return $merged;
 

Вы должны сначала инкапсулировать ответы модели в виде коллекций с collect помощью помощника, затем вы можете объединить их вместе. Затем вывод обрабатывается как логическое объединение, сохраняя данные из обеих моделей в единственном выходе.

Ответ №3:

Вы могли бы сделать что-то вроде этого:

 $live = $this->liveQtyCollection()->keyBy('product_id')
$merged = $this->receivedQtyCollection()->map(function(StockMovement $received) use($live){
    $received->live_qty = $live->get($received->product_id)->live_qty ?? null;
    return $received;
});