СоХабр закрыт.
С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.
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,
self::SCENARIO_UPDATE => self::OP_INSERT,
];
}
class Post extends ActiveRecord
{
// Будем использовать транзакции при указанных сценариях
public function transactions()
{
return [
self::SCENARIO_INSERT => self::OP_INSERT,
self::SCENARIO_UPDATE => 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();
// Устанавливаем нужный сценарий,
// например чтоб запустить транзакцию при сохранении
$post->setScenario(Post::SCENARIO_INSERT);
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)