Помогите со связим

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Помогите со связим

Сообщение systemiv »

Идея такова.
Есть категории, у них есть подкатегории.
При переходе в категорию, у меня показывается "Нет результата", потому что все продукты привязаны по ID к подкатегориям.
Мне нужно что бы при переходе в главную категорию, подгружались все товары из её подкатегорий.
Как это можно сделать?
Связь пробовал задать вот так:

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

public function actionCategory($cat){
        $dataProvider = new CActiveDataProvider('Products', array(
            'pagination' => array(
                'pageSize' => 30,
            ),
            'criteria' => array(
                'with' => array(
                    'subcat' => array(
                        'with' => array(
                            'product' => array(
                                'order' => 't.name_product ASC',
                                'condition' => 't.pid_product = '.$cat,
                            ),
                        ),
                        
                    ),
                ),
                
            ),
        ));
        
        $this->render('category', array(
            'dataProvider' => $dataProvider,
        ));
    }
 
Но онапри переходе в любую категорию подгружает все продукты
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: Помогите со связим

Сообщение rak »

нужно делать не костыль, который будет работать только для определенного уровня вложенности, а выбирать всю ветку категорий
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Но у меня заранее известно что будет именно два уровня и не больше.
А как это сделать хз.
mrix
Сообщения: 125
Зарегистрирован: 2010.08.30, 11:48
Откуда: Россия, Новосибирск

Re: Помогите со связим

Сообщение mrix »

Я бы сделал так.

В класс products добавил бы метод:

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

    /**
     * Именованное условие "из категории ..."
     *
     * @param Category $category
     * @return Products Собственный объект
     */
    public function fromCategory(Category $category)
    {
        //
        $alias = $this->getTableAlias(true);
        $table = $category->getDbConnection()->quoteTableName($category->tableName());

        //подкатегория
        if ($category->parent_id)
        {
            $criteria = array
            (
                'condition' => "{$alias}.category_id = :catid",
                'params' => array('catid' => $category->id),
            );
        }
        else
        {
            $criteria = array
            (
                'join' => "INNER JOIN (SELECT id FROM {$table} WHERE category.parent_id = :catid) AS cat " .
                          "ON {$alias}.category_id = cat.id",
                'params' => array('catid' => $category->id),
            );
        }

        //совмещаем
        $this->getDbCriteria()->mergeWith($criteria);
        return $this;
    } 
В контроллере:

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

    public function actionCategory($cat)
    {
        $category = Category::model()->findByPk($cat);
        if ($category === null)
        {
            throw new CHttpException(404);
        }

        $dataProvider = new CActiveDataProvider(Products::model()->fromCategory($category));
    } 
Писал в браузере, что-то может не работать, но суть такая
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Спасибо большое, сейчас буду разбирать
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Помогите со связим

Сообщение TM123 »

Если у вас категории и подкатегории организованы как дерево и хранятся в одной таблице, то ваша задача - это вопрос правильной настройки условий выборки, а учитывая что у вас глубина всего 2, то получив параметры запроса смотрите, если у пришедшего id parent is null, то в качестве условий поиска добавляете критерий paren=пришедший id, если у id parent not is null, то добавляете критерий поиска id=пришедший id.
Как то так с поправками на ваши особенности. Если бы у вас была глубина больше 2, тогда надо было бы делать разбор дерева, скорее всего пришлось бы разобрать дерево и написать что типа parent in (набор id определенных по пришедшему id). При глубине больше 2, я бы рекомендовал менять бизнес логику и отказываться от вывода всех подкатегорий товара, потому что анализ дерева переменной глубины весьма затратный, если конечно не использовать кэширование.
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Затратный в смысле по запросам? У меня вообще изначально на одной странице при загрузке было 97 запросов к БД. Сейчас уменьшил до 6 с помощью жадной загрузки.
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Помогите со связим

Сообщение TM123 »

Да, каждый запрос - это время на его выполнение и время отнятое им от выполнения других запросов.
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

А можно ли использовать if else прямо в критерии? В формате "Условие : правда ? ложь"
taral14
Сообщения: 236
Зарегистрирован: 2011.02.26, 23:48

Re: Помогите со связим

Сообщение taral14 »

Если вы имеете в виду

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

array(
    'condition'=>(true)?'value1':'value2',
)
 
то да. Так можно делать. Достаточно запустить редактор и увидеть что он не подчеркивает синтаксис
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: Помогите со связим

Сообщение rak »

а ещё главное чтоб читабельно оставалось
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Пробую вот так. Чёт вообще какая то магия началась на сайте

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

return array(
            'categoryRel' => array(self::HAS_MANY, 'Category', 'pid_category', 'joinType'=>'INNER JOIN'),
            'subcat' => array(self::HAS_MANY, 'Category', 'pid_category'),
            'product' => array(self::HAS_MANY, 'Products', 'pid_category', 'through'=>'categoryRel', 'joinType'=>'INNER JOIN'),
        );
 
Проблема в том что у меня по разному называются ключи в таблицах
mrix
Сообщения: 125
Зарегистрирован: 2010.08.30, 11:48
Откуда: Россия, Новосибирск

Re: Помогите со связим

Сообщение mrix »

systemiv писал(а):Пробую вот так.
А зачем?
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Что зачем?
Тот метод не работает
Я пока вижу это единственным выходом
mrix
Сообщения: 125
Зарегистрирован: 2010.08.30, 11:48
Откуда: Россия, Новосибирск

Re: Помогите со связим

Сообщение mrix »

Что там может не работать?

Если категория дочерняя, то выбираются записи с условием WHERE category_id = 123.
Если категория родительская, то выбирается с условием WHERE category_id IN (SELECT id FROM categories WHERE parent_id = 123).

Только я первый раз написал через JOIN, через IN MySQL может не использовать индекс.
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Ну да, там как раз проблемы пошли с тем что он не мог найти ПК, и куча багов с алиасами
Ещё, когда я с ними разобрался, полезла ошибка
Fatal error: Call to a member function getDbConnection() on a non-object in /var/www/shop/protected/models/Products.php on line 28

Вот 28 строчка:
$table = $cat->getDbConnection()->quoteTableName($cat->tableName());
mrix
Сообщения: 125
Зарегистрирован: 2010.08.30, 11:48
Откуда: Россия, Новосибирск

Re: Помогите со связим

Сообщение mrix »

$cat должен быть объектом CActiveRecord
systemiv
Сообщения: 360
Зарегистрирован: 2011.06.26, 22:55
Откуда: Липецк
Контактная информация:

Re: Помогите со связим

Сообщение systemiv »

Пришлось покурить всё)
Там есть некоторые ошибки, но за логику решения огромное спасибо.
Вот результат:

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

if($cat->pid_category != 0){
            $criteria = array(
                'condition' => "{$alias}.pid_product = :idCat",
                'params' => array('idCat' => $cat->id_category),
            );
        }else{
            $criteria = array(
                'join' => "INNER JOIN (SELECT id_category FROM {$table} WHERE pid_category = :idCat) AS cat "."ON {$alias}.pid_product = cat.id_category",
                'params' => array('idCat' => $cat->id_category),
            );
        }
 
taral14
Сообщения: 236
Зарегистрирован: 2011.02.26, 23:48

Re: Помогите со связим

Сообщение taral14 »

можно еще так

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

$criteria=new CDbCriteria;
if($cat->pid_category)
     $criteria->condition="{$alias}.pid_product = :idCat";
else
    $criteria->join="INNER JOIN (SELECT id_category FROM {$table} WHERE pid_category = :idCat) AS cat "."ON {$alias}.pid_product = cat.id_category";
$criteria->params=array(':idCat' => $cat->id_category); 
Также рекомендуется использовать : в ключах в массиве params. Так array(':idCat' => $cat->id_category), а не так array('idCat' => $cat->id_category)
mrix
Сообщения: 125
Зарегистрирован: 2010.08.30, 11:48
Откуда: Россия, Новосибирск

Re: Помогите со связим

Сообщение mrix »

taral14 писал(а):Также рекомендуется использовать : в ключах в массиве params. Так array(':idCat' => $cat->id_category), а не так array('idCat' => $cat->id_category)
Почему? Я всегда использовал без двоеточия, ошибок не было.
Ответить