Вывод связанных товаров для категории с limit

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Вывод связанных товаров для категории с limit

Сообщение slo_nik »

Добрый вечер.
Есть две таблицы, "Категории" и "Товары".
Структура таблицы "Категории"

Код: Выделить всё

id
title
parent_id
Структура таблицы "Товары"

Код: Выделить всё

id
title
price
categories_id // id дочерней категории
В модели Categories есть связи на саму себя и на "Товары"

Код: Выделить всё

    public function getParent()
    {
        return $this->hasOne(Categories::class, ['id' => 'parent_id']);
    }
    
    public function getChildCategories()
    {
        return $this->hasMany(Categories::class, ['parent_id' => 'id']);
    }
    
    public function getProducts()
    {
        return $this->hasMany(Products::class, ['categories_id' => 'id'])->limit(4);
    }
На странице необходимо вывести родительскую категорию с parent_id is null, дочернии категории с parent_id = id и по одному товару для каждой дочерней категории.
То есть в таком виде

Код: Выделить всё

Первая категория

   подкатегория № 1 
   подкатегория № 2
   подкатегория № 3
   подкатегория № 4
   
   товар подкатегории № 1
   товар подкатегории № 2
   товар подкатегории № 3
   товар подкатегории № 4
      
Сейчас запрос выглядит так

Код: Выделить всё

        $categories = Categories::find()
            ->from(['parent' => self::tableName()])
            ->where(['parent.parent_id' => null])
            ->joinWith(['childCategories child'])
            ->joinWith(['products product'])
            ->all();           
В debug панели вижу три запроса

Код: Выделить всё

 
 SELECT `parent`.* FROM `categories` `parent`
     LEFT JOIN `categories` `child` ON `parent`.`id` = `child`.`parent_id`
     LEFT JOIN `products` `product` ON `parent`.`id` = `product`.`categories_id`
     WHERE `parent`.`parent_id` IS NULL
 
 SELECT * FROM `categories` `child` WHERE `parent_id` IN (1, 6)
 
 SELECT * FROM `products` `product` WHERE `categories_id` IN (1, 6) LIMIT 4
Родительская и дочерние категории выводятся без проблем, а товары нет, так как подставляются id родительской категории, а нужно, чтобы подставлялись id дочерних.
Подскажите, как правильно сделать запрос и установить limit на выборку товаров(для каждой подкатегории должен выводится один товар)?
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Вывод связанных товаров для категории с limit

Сообщение unknownby »

Примерно так должно быть, чтобы из дочерних тянуло. Тогда хватает одного джоина и не забываем про дополнительные поля в джоине. Алиасы можно прописывать в связях, чтоб каждый раз их не писать. Выходит такая запись.

Код: Выделить всё

->joinWith('childCategories.products' , false, 'LEFT JOIN')
А лимиты можно по разному делать.
Можно прописать связи hasOne и задать разные сортировки. Например первый, последний или рандомный элемент как для дочерних, так и для продукции.
Можно внутри джоина делать через анонимную функцию что угодно.
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Вывод связанных товаров для категории с limit

Сообщение slo_nik »

unknownby писал(а): 2020.06.18, 07:50
Благодарю за подсказку, только заменил false на true, стали подставляться нужные id и в связи products заменил hasMany на hasOne.

Код: Выделить всё

->joinWith('childCategories.products' , true, 'LEFT JOIN')
Всё работает как требуется.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Вывод связанных товаров для категории с limit

Сообщение unknownby »

slo_nik писал(а): 2020.06.18, 15:06
unknownby писал(а): 2020.06.18, 07:50
Благодарю за подсказку, только заменил false на true, стали подставляться нужные id и в связи products заменил hasMany на hasOne.

Код: Выделить всё

->joinWith('childCategories.products' , true, 'LEFT JOIN')
Всё работает как требуется.
Разница между false и true в том, что будет ли жадная загрузка идентификаторов или нет. По сути будет искать как надо, просто не будет запроса лишнего.
А вот между hasOne и hasMany в том, что первый возвращает один объект, а второй возвращает много в виде массива объектов.
Можно сделать две hasOne связи, но тогда будет возвращать не всё, а только одну запись и если я правильно помню, то первую из списка. :)
Ответить