Реляционная Active Record - контролер/вывод, как?

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
M.Bazaroff
Сообщения: 11
Зарегистрирован: 2014.05.16, 10:46

Реляционная Active Record - контролер/вывод, как?

Сообщение M.Bazaroff »

Привет комьюнити, задача стоит непростая: понять как работать впринципе с реляционной Active Record

на примере двух простых моделей:

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

**** Categories extends CActiveRecord {
 * @property integer $id
 * @property string $name
и

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

**** Products extends CActiveRecord
 * @property integer $id
 * @property string $name
 * @property integer $category_id
 * @property string $image
 * @property string $thumbnail

Я прочитал мануалы, прочитал как это делается в блоге, но так и не понял, как сделать элементарное, вывести имя категории по ее айдишнику в просмотре продукта

Сгенерировал стандартный крад, и заменил как в мануале:

в модели Products :

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

public function relations()
    {
        return array(
            'category'=>array(self::HAS_ONE, 'Categories', 'name'), // тут пробовал ставить айди
        );
    }
 
в ProductsController

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

  public function actionIndex()
    {
        $criteria = new CDbCriteria(array(
            'with' => 'category',
        )); // добавил критерий

        $dataProvider = new CActiveDataProvider('Products', array(
            'criteria' => $criteria, // добавил ага
        ));
        $this->render('index', array(
            'dataProvider' => $dataProvider,
        ));
    }
ну и во вьюхе добавил само собой

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


    <b><?php echo CHtml::encode($data->getAttributeLabel('category')); ?>:</b>
    <?php echo CHtml::encode($data->category); ?> //пробовал $data->category->name); ошибка Trying to get property of non-object 
    <br />

но на выходе у меня выводит:
Category:
нифга тоесть, только лейблу, хотя я ожидаю там увидеть название первой категории (name)


пожалуйста, помогите или натолкните на что почитать чтоб я врубился, потому что нужно будет делать и редактирование и поведения туда..
Аватара пользователя
sluchainiyznak
Сообщения: 617
Зарегистрирован: 2013.05.19, 17:51
Откуда: ХМАО-Югра, г. Сургут
Контактная информация:

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение sluchainiyznak »

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

public function relations()
    {
        return array(
            'category'=>array(self::BELONGS_TO, 'Categories', 'category_id'), 
        );
    } 
я ожидаю там увидеть название первой категории (name)
Так то по связям у вас к продукту привязана всего одна категория

Ну и мануал: http://www.yiiframework.com/doc/guide/1 ... .arr#sec-2
M.Bazaroff
Сообщения: 11
Зарегистрирован: 2014.05.16, 10:46

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение M.Bazaroff »

да, у меня по задумке один продукт и принадлежит только одной категории

не могу понять именно механизм связи, например я сделал вот такое свойство

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

 private $_categoryName;

    public function getCategoryName()
    {


        if ($this->_categoryName === null && $this->categories !== null) {
            $this->_categoryName = $this->categories->name;
        }
        return $this->_categoryName;
    }


    public function setCategoryName($value)
    {
        $this->_categoryName = $value;
    }
но $this->categories - null
M.Bazaroff
Сообщения: 11
Зарегистрирован: 2014.05.16, 10:46

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение M.Bazaroff »

сделал вывод, только теперь поиск не работает, и подозреваю что совсем не круто так делать

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

  public function getCategoryName()
    {
        $category = Categories::model()->findByPk($this->category_id);

        if ($this->_categoryName === null) {
            if ($category != null) {
                $this->_categoryName = $category->name;
            } else if (($this->categories != null)) {
                $this->_categoryName = $this->categories->name;
            }
        }

        return $this->_categoryName;
    }
M.Bazaroff
Сообщения: 11
Зарегистрирован: 2014.05.16, 10:46

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение M.Bazaroff »

я так понимаю не только для меня это сложно?
M.Bazaroff
Сообщения: 11
Зарегистрирован: 2014.05.16, 10:46

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение M.Bazaroff »

Решение оказалось простым, чего я и добивался, пока пытался решить нагородил велосипедов но они не работают совсем :)
основная проблема это неверное определение типа отношения, нужно было сделать BELONGS_TO а не HAS_ONE

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

'category' => array(self::BELONGS_TO, 'Categories', 'category_id')
Добавив геттер/сеттер получаем еще одно свойство модели которое используем при выводе.
Для установки значения категории используется поле category_id, вот такой дропдаун (YiiStrap)

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

echo $form->dropDownListControlGroup($model, 'category_id',
        CHtml::listData(Categories::model()->findAll(), 'id', 'name')
    );

Полный код модели, с сортировками и поиском http://pastebin.com/49LdZQnQ
Аватара пользователя
borshak
Сообщения: 23
Зарегистрирован: 2014.05.26, 13:19
Контактная информация:

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение borshak »

1. Не столь важно, но по принятым соглашениям модели в Yii надо называть в одиночном, а не множественном падеже. То есть,

Product
Category

а не

Products
Category

2. В вашем случае в модели Product действительно следует использовать BELONGS_TO (продукт ПРИНАДЛЕЖИТ группе)

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

# protected/models/Product.php
public function relations() {
return array(
'category' => array(self::BELONGS_TO, 'Categories', 'category_id'),
);
}
 
а внутри модели Category - HAS_MANY в отношении Product (группа ИМЕЕТ МНОГО продуктов)

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

# protected/models/Category.php
public function relations() {
return array(
'product' => array(self::HAS_MANY, 'Product', 'category_id'),
);
} 
При формировании моделей эти связи Gii создаёт автоматически - при условии, что вы описали внешние ключи в таблицах БД.

3. И собственно обращение к данным связанной таблицы.

В контроллере:

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

$product = Product::model()->findByPk($id);
$categotyName = $product->category->name; 
Контроллер передает модель во вьюв, так что вы сможете использовать там данное обращение для вывода.

Это т.н."ленивая" загрузка. Yii грузит вначале строку из таблицы Product (1-й SQL-запрос), а по требованию (2-я строчка кода) - строку из таблицы Category, то есть 2-й SQL-запрос.

Если на странице будет много продуктов, то такой подход неэффективен, так как очень много обращений к БД. Поэтому есть ещё "жадная"загрузка - когда вы указываете имя связи, а Yii одинм SQL-запросом грузит все связанные данные.

В документации жадная - как и ленивая - загрузка описана в разделе http://www.yiiframework.com/doc/guide/1 ... .arr#sec-3
M.Bazaroff
Сообщения: 11
Зарегистрирован: 2014.05.16, 10:46

Re: Реляционная Active Record - контролер/вывод, как?

Сообщение M.Bazaroff »

borshak писал(а):...
Спасибо!
Ответить