Замените связанный массив коллекции моделей новым отформатированным - PullRequest
4 голосов
/ 02 апреля 2020

У меня есть таблицы order, lamp и lamp_order. В настоящее время я получаю Заказы и их отношения с Лампой. Я также получаю Изображения, связанные с Лампами, например:

 $orders = Order::with('lamps.image')->get();

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

$lamps = DB::table('lamp_order')
            ->where('order_id', $order->id)
            ->select('lamp_id', 'order_id', 'room', DB::raw('count(*) as total'))
            ->groupBy('room')
            ->groupBy('lamp_id')
            ->get();

Теперь я хочу добавить количество и название комнаты в коллекцию «Лампа», поэтому я сделал следующее:

$foundLamp = Lamp::find($lamp->lamp_id);
            $collection = collect($foundLamp);
            $collection->put('count', $lamp->total);
            $collection->put('room', $lamp->room);
            $formattedLampsArray[] = $collection;

Как заменить связанную коллекцию Lamp из Order новой, только что отформатированной ? Это целая функция:

  public function index()
    {
        // Fetch orders with their relationships relationships. 
        $orders = Order::with('lamps.image')->get();

        foreach ($orders as $order) {
            $lamps = DB::table('lamp_order')
                ->where('order_id', $order->id)
                ->select('lamp_id', 'order_id', 'room', DB::raw('count(*) as total'))
                ->groupBy('room')
                ->groupBy('lamp_id')
                ->get();

            $formattedLampsArray = [];

            foreach ($lamps as $lamp) {
                $foundLamp = Lamp::find($lamp->lamp_id);
                $collection = collect($foundLamp);
                $collection->put('count', $lamp->total);
                $collection->put('room', $lamp->room);
                $formattedLampsArray[] = $collection;
            }
        }

        return response()->json([
            'orders' => $orders
        ], 200);
    }

По сути, я бы хотел добавить $formattedLampsArray к каждому $order. Таким образом, я могу легко получить новые отформатированные связанные лампы для каждого заказа во внешнем интерфейсе. Кто-нибудь знает, как я могу «заменить» лампы новыми?

Результат будет выглядеть примерно так:

'id' => 1,
'name' => 'John Doe'
'email' => 'johndoe@gmail.com'
'notes' => 'Lorem ipsum dolor sit amet'
'created_at' => '2020-04-02 12:32:30' 
'updated_at' => '2020-04-02 12:32:30'
'lamps_count' => 20
'grouped_lamps' => [
  [
   'id' => 9
   'name' => 'Lamp 1'
   'fitting' => 'E14'
   'shape' => 'Candle'
   'room' => 'Hall'
   'count' => '5'
  ],
  [
   'id' => 9
   'name' => 'Lamp 1'
   'fitting' => 'E14'
   'shape' => 'Candle'
   'room' => 'Kitchen'
   'count' => '5'
  ],
  [
   'id' => 11
   'name' => 'Lamp 2'
   'fitting' => 'E27'
   'shape' => 'Pear'
   'room' => 'Livingroom'
   'count' => '5'
  ],
  [
   'id' => 12
   'name' => 'Lamp 3'
   'fitting' => 'E27'
   'shape' => 'Pear'
   'room' => 'Sleepingroom'
   'count' => '5'
  ],
];

Ответы [ 2 ]

3 голосов
/ 02 апреля 2020

Я думаю, это то, что вы ищете
Существует метод withCount(), который делает ->select('lamp_id', 'order_id', 'room', DB::raw('count(*) as total')) работу для вас
https://laravel.com/docs/5.8/eloquent-relationships#counting -по-родственные модели

Обратите внимание, что поскольку свойство ->lamps на самом деле является отношением, мы не можем изменить его, поэтому мы делаем его скрытым и создаем новое свойство с именем grouped_lamps

public function index()
{
    $orders = Order::withCount('lamps')
        ->with('lamps.image')
        ->get()->map(static function (Order $order) {
            $order->lamps->each(static function (Lamp $lamp) {
                $lamp->room = $lamp['pivot']['room'];
            });

            return $order;
        })->each(function (Order $order) {
            $order->grouped_lamps = $order->lamps->groupBy(['room', 'id']);
            $order->makeHidden('lamps');

            return $order;
        });

    return response()->json([
        'orders' => $orders,
    ], 200);
}

Редактировать

Я не уверен, что это то, что вы ищете, но здесь мы go

Сначала нам нужно получить этот дополнительный столбец room с нашим отношением, поэтому убедитесь, что в вашем Order модель, которую вы добавляете ->withPivot('room') вот так

public function lamps()
{
    return $this->belongsToMany(Lamp::class, 'lamp_order', 'lamp_id', 'order_id')
        ->withPivot('room');
}

И вот код, нам больше не нужно иметь grouped_lamps

public function index()
{
    $orders = Order::withCount('lamps')
        ->with('lamps.image')
        ->get()->map(function (Order $order) {
            $order->lamps->each(static function (Lamp $lamp) use ($order) {
                $lamp->room = $lamp['pivot']['room'];
                $lamp->count = $order->lamps_count;
            });

            return $order;
        });

    return response()->json([
        'orders' => $orders,
    ], 200);
}

Надеюсь, это поможет

Окончательное редактирование
Хорошо, просмотрев мой код, я обнаружил, что допустил честную ошибку

Соотношение ламп foreign_key и local_key Неправильное размещение. Это правильная форма

public function lamps()
{
    return $this->belongsToMany(Lamp::class, 'lamp_order', 'order_id', 'lamp_id')
        ->withPivot('room');
}

А вот и новая версия кода
Обратите внимание, что если вы в порядке с предыдущим форматом, вам не нужно использовать ниже код

public function index()
{
    $orders = Order::withCount('lamps')
        ->with('lamps.image')
        ->get()
        ->map(static function (Order $order) {
            $order->lamps->each(static function (Lamp $lamp) {
                $lamp->room = $lamp['pivot']['room'];
            });

            return $order;
        })->each(function (Order $order) {
            $groupedLamps = $order->lamps->groupBy('room');
            $order->lamps->each(function (Lamp $lamp) use ($groupedLamps) {
                $lamp->count = $groupedLamps[$lamp->room]->count();
            });
        });

    return response()->json([
        'orders' => $orders,
    ], 200);
}

И вы получите такой результат

{
    "orders": [
        {
            "id": 1,
            "title": "ut fugit facilis",
            "lamps_count": 5, // Total lamps owned by this order
            "lamps": [
                {
                    "title": "ab sunt nostrum",
                    "room": "kitchen",
                    "count": 3, // Total number of kitchen lamps of order_id 1
                    "pivot": {
                        "order_id": 1,
                        "lamp_id": 1,
                        "room": "kitchen"
                    }
                },
                {
                    "title": "omnis dicta rerum",
                    "room": "hall",
                    "count": 2, // Total number of hall lamps of order_id 1
                    "pivot": {
                        "order_id": 1,
                        "lamp_id": 2,
                        "room": "hall"
                    }
                },
                {
                    "title": "eligendi deserunt et",
                    "room": "hall",
                    "count": 2, // Total number of hall lamps of order_id 1
                    "pivot": {
                        "order_id": 1,
                        "lamp_id": 3,
                        "room": "hall"
                    }
                },
                {
                    "title": "modi ad ea",
                    "room": "kitchen",
                    "count": 3, // Total number of kitchen lamps of order_id 1
                    "pivot": {
                        "order_id": 1,
                        "lamp_id": 4,
                        "room": "kitchen"
                    }
                },
                {
                    "title": "eos neque consequatur",
                    "room": "kitchen",
                    "count": 3, // Total number of kitchen lamps of order_id 1
                    "pivot": {
                        "order_id": 1,
                        "lamp_id": 5,
                        "room": "kitchen"
                    }
                }
            ]
        },
        {
            "id": 2,
            "title": "sapiente velit quas",
            "lamps_count": 2,
            "lamps": [
                {
                    "title": "eligendi deserunt et",
                    "room": "kitchen",
                    "count": 2,
                    "pivot": {
                        "order_id": 2,
                        "lamp_id": 3,
                        "room": "kitchen"
                    }
                },
                {
                    "title": "modi ad ea",
                    "room": "kitchen",
                    "count": 2,
                    "pivot": {
                        "order_id": 2,
                        "lamp_id": 4,
                        "room": "kitchen"
                    }
                }
            ]
        },
        {
            "id": 3,
            "title": "itaque sint voluptas",
            "lamps_count": 4,
            "lamps": [
                {
                    "title": "omnis dicta rerum",
                    "room": "kitchen",
                    "count": 1,
                    "pivot": {
                        "order_id": 3,
                        "lamp_id": 2,
                        "room": "kitchen"
                    }
                },
                {
                    "title": "eligendi deserunt et",
                    "room": "living_room",
                    "count": 1,
                    "pivot": {
                        "order_id": 3,
                        "lamp_id": 3,
                        "room": "living_room"
                    }
                },
                {
                    "title": "modi ad ea",
                    "room": "hall",
                    "count": 2,
                    "pivot": {
                        "order_id": 3,
                        "lamp_id": 4,
                        "room": "hall"
                    }
                },
                {
                    "title": "eos neque consequatur",
                    "room": "hall",
                    "count": 2,
                    "pivot": {
                        "order_id": 3,
                        "lamp_id": 5,
                        "room": "hall"
                    }
                }
            ]
        }
    ]
}
0 голосов
/ 14 апреля 2020

Ответ AH.Pooladvand помог мне в правильном направлении, но он не соответствовал моим требованиям. Вот почему я все еще дал ему награду +50. Мой друг сказал мне, что я должен запросить сводную таблицу напрямую. Я объединил оба ответа в этот кусок кода.

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

   public function index()
    {

        // Get all Orders and count the amount of related Lamps.
        $orders = Order::withCount('lamps')
            ->with('lamps.image') // Also fetch related Image of the Lamp
            ->get()
            ->map(static function (Order $order) {
                // For each lamp count how many times it occurs per room.
                $order->lamps->each(static function (Lamp $lamp) {
                    $countedLamps = DB::table('lamp_order')
                        ->select(DB::raw('*, count(*) as count_lamps'))
                        ->groupBy('lamp_id', 'room')
                        ->get();

                    foreach ($countedLamps as $countedLamp) {
                        // If lamp_id and room are the same then add the count and room to the Lamp. 
                        if ($countedLamp->lamp_id == $lamp['id'] && $countedLamp->room == $lamp['pivot']['room']) {
                            $lamp->count = $countedLamp->count_lamps;
                            $lamp->room = $countedLamp->room;
                        }
                    }
                });

                // Remove duplicate Lamps an create an new attribute in the collection array.
                $collection = collect($order->lamps);
                $order->ordered_lamps = $collection->unique()->values()->all();
                // Make unordered Lamps array hidden.
                $order->makeHidden('lamps');
                return $order;
            });

        return response()->json([
            'orders' => $orders,
        ], 200);
    }

Я выбираю все Ордена, сразу же подсчитываю количество Ламп в этом Ордене и получаю соответствующее Изображение этого Лампа. Для каждого Ордена я считаю лампы по room и lamp_id. Для каждого из этих $groupedLamp я делаю грязную проверку, чтобы добавить переменную count и room к самому объекту lamp. Затем в конце я удаляю дубликаты из массива lamp, скрываю их и создаю переменную order_lamps. Любые улучшения приветствуются. Я отредактирую этот ответ, когда он будет оптимизирован.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...