СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H Yii2. Связи Active Record в черновиках Tutorial

Yii
Yii2 еще только в бета-тестировани, но, видимо, это никого не пугает. Кто-то просто изучает новые возможности, но многие начали использовать его даже в продакшене и под дулом пистолета отказываются даже смотреть на код первой версии.

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

Я решил написать свой рецепт. Возможно, вы посчитаете его полезным, возможно поймёте как делать не надо. В любом случае, надеюсь, материал будет полезен.


Что нам предлагает фреймворк для работы со связями?


Связи в новой версии фреймворка объявляются при помощи геттеров:

public function getCategory()
{
    return $this->hasOne(Category::className(), ['id' => 'category_id']);
}

Геттер возвращает ActiveQuery, который можно дополнительно настроить перед загрузкой связанной модели:
$posts = Category::find($id)->getPosts()->limit(5)->order('created_at')->all();

Замечание:
Когда Вы используете магию $post->category, вместо геттера, помните, так вы получаете результат запроса Query-объекта.
Другими словами $post->category === $post->getCategory()->one()

Методы работы со связями

populateRelation($relationName, $relatedModelOrArray) -добавляет связанную модель в родительскую.

Замечание:
Этот метод не проверяет, объявлена ли связь между этими моделями (геттер), а также не устанавливает нужные значения в атрибуты.

$post = new Post();
$post->populateRelation('category', new Category());
$post->populateRelation('tags', [new Tag(), new Tag()]);

link($relationName, relatedModel, $extraColumns = []) — в отличии от populateRelation, этот метод, кроме добавления связанной модели, также привязывает модели, расставляя нужные индексы. Сразу он сохраняет ТОЛЬКО связанную модель. $extraColumns сохранятся в pivot table, если связь осуществляется через неё.

$post = new Post();
$post->link('category', new Category());
$post->link('tags', new Tag());
$post->link('tags', new Tag());

Вам, возможно, захочется сохранять модели вместе со связями в одной транзакции. Для этого в Yii2 есть встроенные средства:
public function transactions()
{
  return [
    // scenario name => operation (insert, update or delete)
     self::SCENARIO_DEFAULT => self::OP_INSERT | self::OP_UPDATE,
  ];
}

Это лишь некоторые методы. Остальные Вы найдёте в официальной документации.

Пример


Теперь я хочу показать как их можно использовать на примере.

Модель
Контролер

Вместо заключения


Если вы знаете что такое Yii Framework, живете в Кишиневе (Молдова) или поблизости, присоединяйтесь к нам! Мы хотим собраться в оффлайне.
Подробности здесь!

Ждем всех!

комментарии (6)

0
Ekstazi ,  
Спасибо, еще бы про контроль доступа в Yii2 рассказал.
0
codru ,  
Там в документации всё достаточно подробно описано, как мне показалось. По крайней мере с rbac разобраться проблем не составило. Ссылка
+3
AlexGx ,  

Использую Yii2 на продакшене. Полет отличный.

Хочу сделать небольшую ремарку по связям для тех кто будет переходить с Yii1. В Yii2 нет связи BELONGS_TO, вместо нее используют hasOne с обратной нотацией.

Пример. Было

...
 'option' => array(self::BELONGS_TO, 'Option', 'option_id'),
...


Стало
public function getOption()
{
    return $this->hasOne(Option::className(), ['id' => 'option_id']);
}
+1
AstRonin ,   * (был изменён)
опять мало… какие-то выдержки из форума…
на tutorial не тянет
+2
DIAgen ,   * (был изменён)
Не описали viaTable, Lazy и Eager Загрузку, inverseOf, joinWith и т.д, так это заметка об AR Relational Data.
0
ATLANT1S ,  

Сдаётся мне, на 8 строке ошибка. Заполнять надо бы $tags.

    public function setTagsString($value)
    {
        $tags = [];
      
        foreach (explode(',' $value) as $name) {
             $tag = new Tag();
             $tag->name = $name;
             $tag[] = $tag;
        }
       
        $this->setTags($tags);
    }