laravel, несколько вопросов


VHS
216

Начинаю окунаться в лару, никак не могу понять, как мне сделать следующее:

Три таблицы:

catalogs

catalog_product

product

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

Связь между catalogs и  catalog_product не по первичному ключу, а по уникальному UID.

Имена полей в  catalog_product catalog и product

Первичный ключ продукта — UID

1) Как правильно описать взаимосвязь через таблицу, для получения всех продуктов каталога?

2) Как получить все продукты текущего и дочерних каталогов (используется nested sets) ? Сейчас получаю не совсем красиво, через подготовку массива и whereIn


VHS
Отвечу сам себе. Все отлично работает через 

hasManyThrough

с одним нюансом — в отладчике нет информации о запросе, которым это было сделано. Что тут за магия — я не могу понять.


Кирилл Арутюнов
Лог запросов из отладчика в студию. Насколько я помню, там надо указывать опцию для явного джоина, чтобы был сложный запрос с джоином, либо илокент делает запросы с подзапросами или в несколько отдельных запросов получает данные и сводит их вместе.

VHS

Кирилл, спасибо за отклик. Удивительнейшим образом сегодня все заработало. 

Все оказалось просто. Запрос был частью системы динамического роутинга каталога, очень похоже на вот этот пример (https://gtxtymt.xyz/blog/laravel-pages-from-database). Т.к. эту часть я делал достаточно давно, а потом на несколько месяцев забросил проект, то и воспоминаний о кешировании у меня не осталось =) Убрал ->with(‘products’), почистил кэш, подзапросы пошли. 

Работа с динамическими страницами в Laravel
Работа с динамическими страницами в Laravel
  • 2019.03.16
  • gtxtymt.xyz
Очень часто, я бы даже сказал практически в каждом проекте возникает необходимость создать «динамические страницы» — страницы с одной сущностью, разным содержимым и без какого-либо паттерна для конфигурации конечного адреса, по которому сущность будет отображаться. Конечный адрес может иметь неограниченное количество уровней — от банального до…

Неуч
Ссылки не индексируются.

VHS

Посмотри на мою дату регистрации и подумай, нужна ли мне эта информация или нет?)

Теперь осталось разобраться со второй частью вопроса — как красиво отобрать все продукты в текущей и дочерних каталогах ) 

Пока сделано по старинке : 

$groupsArray[] = $group->UID;
$descendants = $group->descendants()->defaultOrder()->get();
foreach ($descendants as $model) {
$groupsArray[] = $model->UID;
}


$products = CatalogProduct::whereIn('catalog_products.catalog_UID', $groupsArray)
->leftJoin('products', 'products.UID', '=', 'catalog_products.product_UID')
->where('products.price', '>', 0)
->orderBy($sortField, $sortWay)
->get();

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


Кирилл Арутюнов

Дублей можно избежать с помощью `distinct()`. Надо играться и смотреть итоговый запрос.

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

И в `whereIn` ты можешь подзапрос положить по типу `WHERE IN (SELECT id FROM …)`. Тогда не придётся логику какую-то на php описывать. На малой нагрузке так будет ок, а на большой стоит смотреть на перфоманс, чтобы понимать какой из вариантов будет лучше отрабатывать.

PS. Отвратительный редактор сообщений, ещё и без поддержки маркдауна. Я сломал всё вокруг, но не смог оформить инлайн-код, поэтому пусть будет так, как я написал.


VHS
Кирилл Арутюнов #:
distinct

Благодарю за советы!

distinct использовать не удалось, но получился не сильно страшный по производительности, и главное рабочий запрос

$products = CatalogProduct::select('*')->from(
DB::table('catalog_products')
->selectRaw('MAX(catalog_UID) AS catalog_UID, product_UID')
->whereIn('catalog_UID', $groupsArray)
->groupBy('product_UID')
)
->leftJoin('products', function ($join) {
$join->on('products.UID', '=', 'product_UID')
->where('products.price', '>', 0);
})

->orderBy($sortField, $sortWay)
->paginate(12);

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *