laravel order by with joins

111
27 мая 2021, 10:00

Есть 4 таблицы:

factories
factory_contacts
factory_notifications
users

Мы, как пользователь заходим на страницу и видим список заводов. Открывая завод мы видим список контактов, открвая контакт мы видим с ним переписку. В зависимости от того с какого пользователя зашли, разная переписка соответсвенно.

Так вот, переписка работает таким образом, что тупо отлавливает входящие сообщения из почты. И каждый раз когда приходит новое сообщение, в таблице factory_notifications в колонку new_mail плюсуется 1 (всего там три колонки - factory_contact_id и user_id, ну ил new_mail);

Проблема в том, что мне нужно отсорировать вывод factories по последнему сообщению. То есть для каждого пользователя сортировка будет разная.

Как все сделать одним запросом и возможно ли это вообще?

Остановился на вот таком извращении, которое все равно не сортирует правильно:

$factories = Factory::orderBy($sortBy, $orderBy)->with('contacts')->with('discounts')->with('markups')->with('pickupAddresses')->with('legalAddress')->with('realAddress')->with('postAddress')->paginate($request->perPage);
            foreach ($factories as $factory) {
                $lastMessage = 0;
                foreach ($factory->contacts as $contacts) {
                    foreach ($contacts->notifications as $notification) {
                        if ($lastMessage < strtotime($notification->updated_at)) {
                            $lastMessage = strtotime($notification->updated_at);
                        }
                    }
                }
                $factory->last_message_time = date('d-m-Y H:i:s', $lastMessage);
            }
            if ($sortBy == 'updated_at') {
                if ($orderBy == 'ASC') {
                    $factories->sortBy('last_message_time');
                } else {
                    $factories->sortByDesc('last_message_time');
                }
            }

UPD: Удалось получить нужный вариант, но с дубликатами. Distinct не получается впихнуть... Может есть какие предложения?

Paginator::currentPageResolver(function () use ($currentPage) {
                return $currentPage;
            });
            $factories = Factory::select(DB::raw("factories.*, factory_contacts.*, factory_notifications.updated_at AS last_message_time"))
                    ->leftJoin('factory_contacts', 'factories.id', '=', 'factory_contacts.factory_id')
                    ->leftjoin('factory_notifications', function ($join) use ($request) {
                          $join->on('factory_notifications.id', '=', DB::raw("(SELECT id FROM factory_notifications WHERE factory_notifications.factory_contact_id = factory_contacts.id AND factory_notifications.user_id = 6 ORDER BY factory_notifications.updated_at DESC)"));
                     })->orderByRaw('factory_notifications.updated_at DESC NULLS LAST')
                     ->with('contacts')->with('discounts')->with('markups')->with('pickupAddresses')->with('legalAddress')->with('realAddress')->with('postAddress')->paginate($request->perPage);
            return response()->json($factories, 200);

UPD2: Решил вот так, но ох как не нравится мне это решение:

$orderBy = $request->descending ? 'DESC NULLS LAST' : 'ASC NULLS LAST';
            $sortBy = $request->sortBy ? $request->sortBy : 'factory_notifications.updated_at';
            $currentPage = $request->page;
            Paginator::currentPageResolver(function () use ($currentPage) {
                return $currentPage;
            });
            // Don't touch!! Or check app\Providers\AppServiceProvider.php before making changes!
            $factories = Factory::select(DB::raw("factories.*, factory_contacts.factory_id, factory_notifications.updated_at AS last_message_time"))
                    ->leftJoin('factory_contacts', 'factories.id', '=', 'factory_contacts.factory_id')
                    ->leftjoin('factory_notifications', function ($join) use ($request) {
                          $join->on('factory_notifications.id', '=', DB::raw("(SELECT id FROM factory_notifications WHERE factory_notifications.factory_contact_id = factory_contacts.id AND factory_notifications.user_id = $request->user_id ORDER BY factory_notifications.updated_at DESC)"));
                     })->orderByRaw($sortBy.' '.$orderBy)
                     ->with('contacts')->with('discounts')->with('markups')->with('pickupAddresses')->with('legalAddress')->with('realAddress')->with('postAddress')->get();
            $factories = $factories->unique('factory_id')->paginate($request->perPage);
            return response()->json($factories, 200);
        }
READ ALSO
Замена подстроки с помощью регулярного выражения

Замена подстроки с помощью регулярного выражения

Есть строкаМне нужно по регулярному выражению обернуть все совпадения в тег span

139
exec в php не выводит ответ

exec в php не выводит ответ

Что выводится в командной строке:

129
Выбрать четыре дня текущей недели, включая сегодняшний и три случайных

Выбрать четыре дня текущей недели, включая сегодняшний и три случайных

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

92
пространства имен php 7.3

пространства имен php 7.3

У меня в пространстве имен Test, есть класс A

111