СоХабр закрыт.
С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.
 Yii2 еще только в бета-тестировани, но, видимо, это никого не пугает. Кто-то просто изучает новые возможности, но многие начали использовать его даже в продакшене и под дулом пистолета отказываются даже смотреть на код первой версии.
 Yii2 еще только в бета-тестировани, но, видимо, это никого не пугает. Кто-то просто изучает новые возможности, но многие начали использовать его даже в продакшене и под дулом пистолета отказываются даже смотреть на код первой версии.public function getCategory()
{
    return $this->hasOne(Category::className(), ['id' => 'category_id']);
}
$posts = Category::find($id)->getPosts()->limit(5)->order('created_at')->all();
Замечание:
Когда Вы используете магию $post->category, вместо геттера, помните, так вы получаете результат запроса Query-объекта.
Другими словами $post->category === $post->getCategory()->one()
Замечание:
Этот метод не проверяет, объявлена ли связь между этими моделями (геттер), а также не устанавливает нужные значения в атрибуты.
$post = new Post();
$post->populateRelation('category', new Category());
$post->populateRelation('tags', [new Tag(), new Tag()]);
$post = new Post();
$post->link('category', new Category());
$post->link('tags', new Tag());
$post->link('tags', new Tag());
public function transactions()
{
  return [
    // scenario name => operation (insert, update or delete)
     self::SCENARIO_DEFAULT => self::OP_INSERT | self::OP_UPDATE,
  ];
}
class Post extends ActiveRecord
{
    // Будем использовать транзакции при указанных сценариях
    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_INSERT | self::OP_UPDATE,
        ];
    }
    public function getTags()
    {
        return $this->hasMany(Tag::className(), ['id' => 'tag_id'])
            ->viaTable('post_tag', ['post_id' => 'id']);
    }
    // Я предлагаю использовать сеттеры для связей,
    // хотя это дополнительное телодвижение,
    // но совсем не сложно писать сразу рядом с геттером.
    // Зато очень удобно, т.к. сразу можно делать дополнительные 
    // изменения модели
    public function setTags($tags)
    {
        $this->populateRelation('tags', $tags);
        $this->tags_count = count($tags);
    }
    // Сеттер для получения тегов из строки, разделенных запятой
    public function setTagsString($value)
    {
        $tags = [];
      
        foreach (explode(',' $value) as $name) {
             $tag = new Tag();
             $tag->name = $name;
             $tag[] = $tag;
        }
       
        $this->setTags($tags);
    }
    public function getCover()
    {
        return $this->hasOne(Image::className(), ['id' => 'cover_id']);
    }
    public function setCover($cover)
    {
        $this->populateRelation('cover', $cover);
    }
    public function getImages()
    {
        return $this->hasMany(Image::className(), ['post_id' => 'id']);
    }
    public function setImages($images)
    {
        $this->populateRelation('images', $images);
        if (!$this->isRelationPopulated('cover') && !$this->getCover()->one()) {
            $this->setCover(reset($images));
        }
    }
    public function loadUploadedImage()
    {
           $images = [];
           foreach (UploadedFile::getInstances(new Image(), 'image') as $file) {
                $image = new Image();
                $image->name = $file->name;
                $images[] = $image;
           }
           $this->setImages($images);
    }
    public function beforeSave($insert)
    {
        if (!parent::beforeSave($insert)) {
            return false;
        }
       // В beforeSave мы сохраняем связанные модели
       // которые нужно сохранить до основной, т.е. нужны их ИД
       // Не волнуйтесь о транзакции т.к. мы настроили,
       // она будет начата при вызове метода `insert()` и `update()`
       // Получаем все связанные модели, те что загружены или установлены
       $relatedRecords = $this->getRelatedRecords();
       if (isset($relatedRecords['cover'])) {
           $this->link('cover', $relatedRecords['cover']);
       }
      
       return true;
    }
    public function afterSave($insert)
    {
       // В afterSave мы сохраняем связанные модели
       // которые нужно сохранять после основной модели, т.к. нужен ее ИД
       // Получаем все связанные модели, те что загружены или установлены
       $relatedRecords = $this->getRelatedRecords();
       if (isset($relatedRecords['tags'])) {
           foreach ($relatedRecords['tags'] as $tag) {
               $this->link('tags', $tag);
           }
       }
          
       if (isset($relatedRecords['images'])) {
           foreach ($relatedRecords['images'] as $image) {
               $this->link('images', $image);
           }
       }
    }
}
class PostController extends Controller
{
    public function actionCreate()
    {
        $post = new Post();
        if ($post->load(Yii::$app->request->post())) {
            // Сохраняем загруженные файлы
            $this->loadUploadedImages();
            if ($post->save()) {
                return $this->redirect(['view', 'id' => $post->id]);
            }
        }
          
        return $this->render('create', [
            'post' => $post,
        ]);
     }
}
комментарии (6)