Связь Laravel Eloquent с группой по атрибутам из двух моделей

У меня две модели InvoiceHeader и InvoiceDetail. InvoiceHeader имеет следующие атрибуты (среди прочего): id, pos_id, pos_description и date. InvoiceDetail имеет следующие атрибуты (среди прочего): id, invoice_header_id, pct, price. Между двумя моделями существует отношение «один ко многим».

Я хочу сгруппировать по pos_id и date из InvoiceHeader и по pct из InvoiceDetail. И с этим я хотел бы получить сумму цены.

Из того, что я обнаружил, невозможно сгруппировать по обеим моделям одновременно, поскольку с Eloquent не выполняются фактические соединения. Итак, я решил, что могу сгруппировать по атрибуту pct в файле InvoiceDetail. Я делаю что-то вроде этого:

$invoices = \App\InvoiceHeader::with(['details' => function ($query) {
        $query->select('pct')
            ->selectRaw('SUM(price) AS price')
            ->groupBy(['invoice_header_id', 'pct']);
    }])
    ->whereBetween('date', ['2018-01-01', '2018-07-31'])
    ->select(['pos_id', 'pos_description', 'date'])
    ->get();

И именно здесь я застрял. Мне нужно сгруппировать по pos_id, pos_description по InvoiceHeader и сгруппировать по pct по InvoiceDetail.

Отсюда я иду по маршруту, который я считаю не самым лучшим/простым. У меня есть коллекция Eloquent из InvoiceHeader, связанная с ее коллекцией InvoiceDetail. Я чувствую, что должен поработать над этим, но так как я не могу понять, как преобразовать его в коллекцию Laravel. Поскольку это единственное, что немного приблизило меня к тому, что я получил, я решил, что смогу с этим справиться. Однако, если у кого-то есть лучшее предложение, пожалуйста, поделитесь. А пока вот что у меня получилось.

Я делаю коллекцию Laravel из коллекции Eloquent как таковую:

$collection = collect();
foreach ($invoices as $invoice) {
    foreach ($invoice->details as $detail) {
        $collection->push([
            'pos_id' => $invoice->pos_id,
            'pos_description' => $invoice->pos_description,
            'date' => $invoice->date,
            'pct' => $detail->pct,
            'price' => $detail->price,
        ]);
    }
}

Это приводит меня к чему-то вроде

$collection = [
    [
        'pos_id'          => 1,
        'pos_description' => 'Somewhere',
        'date'            => '2018-02-28',
        'pct'             => 6,
        'price'           => 68.94
    ], [
        'pos_id'          => 1,
        'pos_description' => 'Somewhere',
        'date'            => '2018-02-28',
        'pct'             => 21,
        'price'           => 99.99
    ], [
        'pos_id'          => 1,
        'pos_description' => 'Somewhere',
        'date'            => '2018-02-28',
        'pct'             => 21,
        'price'           => 82.64
    ], [
        'pos_id'          => 1,
        'pos_description' => 'Somewhere',
        'date'            => '2018-03-31',
        'pct'             => 21,
        'price'           => 431.45
    ]
]

Вот где я хочу получить или что-то подобное:

$newCollection = [
    [
        'pos_id'          => 1,
        'pos_description' => 'Somewhere',
        'date'            => '2018-02-28',
        'details'     => [
            [
               'pct'   => 6,
               'price' => 68.94
            ], [
               'pct'   => 21,
               'price' => 182.63
            ]
        ]
    ], [
        'pos_id'          => 1,
        'pos_description' => 'Somewhere',
        'date'            => '2018-03-31',
        'details'     => [
            [
               'pct'   => 21,
               'price' => 431.45
            ]
        ]
    ]
]

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

Отказ от ответственности: большая часть кода основана на рабочем коде. Чтобы упростить вещи, я упростил некоторые вещи.


person Ruben Colpaert    schedule 23.07.2018    source источник
comment
Зачем вам нужна группа вместо того, чтобы просто связывать детали с первичным ключом заголовка? В этом весь смысл внешних ключей.   -  person Devon    schedule 23.07.2018
comment
Итак, вам удалось найти решение своего вопроса?   -  person Andrew Naguib    schedule 23.07.2018
comment
@Девон, потому что мне нужна сумма цены за pos_id, дату и процент. Я предполагаю, что вам нужно где-то объявить, что вам нужно что-то сгруппировать, чтобы получить сумму по этой группе?   -  person Ruben Colpaert    schedule 23.07.2018
comment
@andrew, у меня нет. я хочу добраться до $newCollection, но понятия не имею, как туда добраться.   -  person Ruben Colpaert    schedule 23.07.2018
comment
Предложение › Если у кого-то есть лучшее предложение, поделитесь им. смутил меня.   -  person Andrew Naguib    schedule 23.07.2018
comment
Однако у вас, кажется, есть ответ, вы просто не правильно строите коллекцию, не так ли?   -  person Andrew Naguib    schedule 23.07.2018
comment
@andrew, это, и у меня еще нет суммы за pos_id, дату и процент. Пока я не начну создавать новую коллекцию Laravel, она группируется по invoice_id и pct.   -  person Ruben Colpaert    schedule 23.07.2018
comment
Вместо использования отношения просто используйте соединение. В любом случае вы действительно не видите выгоды от использования здесь отношений, поскольку вам не нужно получать связанные модели.   -  person Devon    schedule 23.07.2018


Ответы (1)


Как насчет такой базовой итерации:

$dirtyColl = [];
foreach ($collection as $key => $value) {
    $dirtyColl[$value['date']]['pos_id'] = $value['pos_id'];
    $dirtyColl[$value['date']]['pos_description'] = $value['pos_description'];
    $dirtyColl[$value['date']]['date'] = $value['date'];
    $dirtyColl[$value['date']]['details'][$value['pct']]['pct'] = $value['pct'];
    $dirtyColl[$value['date']]['details'][$value['pct']]['price'] += $value['price'];
}

print_r(array_values($dirtyColl));

приводит к

Array
(
    [0] => Array
        (
            [pos_id] => 1
            [pos_description] => Somewhere
            [date] => 2018-02-28
            [details] => Array
                (
                    [6] => Array
                        (
                            [pct] => 6
                            [price] => 68.94
                        )

                    [21] => Array
                        (
                            [pct] => 21
                            [price] => 182.63
                        )

                )

        )

    [1] => Array
        (
            [pos_id] => 1
            [pos_description] => Somewhere
            [date] => 2018-03-31
            [details] => Array
                (
                    [21] => Array
                        (
                            [pct] => 21
                            [price] => 431.45
                        )

                )

        )

)

Может быть, просто снова используйте array_values ​​​​для «деталей».

person Bert Maurau    schedule 23.07.2018