category_id = $categoryId; $post->title = $title; $post->slug = $slug; $post->description = $description; $post->content = $content; $post->meta = $meta; $post->status = self::STATUS_DRAFT; $post->created_at = time(); $post->comments_count = 0; $post->published_at = $published_at; $post->video = $video; return $post; } public function setImage(UploadedFile $image): void { $this->image = $image; } public function edit($categoryId, $title, $slug, $description, $content, $published_at, $video, Meta $meta): void { $this->category_id = $categoryId; $this->title = $title; $this->slug = $slug; $this->description = $description; $this->content = $content; $this->meta = $meta; $this->published_at = $published_at; $this->video = $video; } /** * @inheritdoc */ public static function tableName() { return 'blog_posts'; } /** * @inheritdoc */ public function attributeLabels() { return [ 'id' => Yii::t('blog', 'ID'), 'category_id' => Yii::t('blog', 'Category'), 'published_at' => Yii::t('blog', 'Published At'), 'created_at' => Yii::t('blog', 'Created At'), 'updated_at' => Yii::t('blog', 'Updated At'), 'title' => Yii::t('blog', 'Title'), 'description' => Yii::t('blog', 'Description'), 'content' => Yii::t('blog', 'Content'), 'image' => Yii::t('blog', 'Image'), 'video' => Yii::t('blog', 'Video'), 'status' => Yii::t('blog', 'Status'), 'meta_json' => Yii::t('blog', 'Meta Json'), 'comments_count' => Yii::t('blog', 'Comments Count'), 'views' => Yii::t('blog', 'Views'), 'slug' => Yii::t('blog', 'Slug'), 'meta.title' => Yii::t('blog', 'Meta Title'), 'meta.description' => Yii::t('blog', 'Meta Description'), 'meta.keywords' => Yii::t('blog', 'Meta Keywords'), ]; } public function activate(): void { if ($this->isActive()) { throw new \DomainException('Post is already active.'); } $this->status = self::STATUS_ACTIVE; } public function draft(): void { if ($this->isDraft()) { throw new \DomainException('Post is already draft.'); } $this->status = self::STATUS_DRAFT; } public function isActive(): bool { return $this->status == self::STATUS_ACTIVE; } public function isDraft(): bool { return $this->status == self::STATUS_DRAFT; } public function getSeoTitle(): string { return $this->meta->title ?: $this->title; } // Tags public function assignTag($id): void { $assignments = $this->blogTagAssignments; foreach ($assignments as $assignment) { if ($assignment->isForTag($id)) { return; } } $assignments[] = BlogTagAssignment::create($id); $this->blogTagAssignments = $assignments; } public function revokeTag($id): void { $assignments = $this->blogTagAssignments; foreach ($assignments as $i => $assignment) { if ($assignment->isForTag($id)) { unset($assignments[$i]); $this->blogTagAssignments = $assignments; return; } } throw new \DomainException('Assignment is not found.'); } public function revokeTags(): void { $this->blogTagAssignments = []; } // Comments public function addComment($userId, $parentId, $text): BlogComment { $parent = $parentId ? $this->getComment($parentId) : null; if ($parent && !$parent->isActive()) { throw new \DomainException('Cannot add comment to inactive parent.'); } $comments = $this->blogComments; $comments[] = $comment = BlogComment::create($userId, $parent ? $parent->id : null, $text); $this->updateComments($comments); return $comment; } public function editComment($id, $parentId, $text): void { $parent = $parentId ? $this->getComment($parentId) : null; $comments = $this->blogComments; foreach ($comments as $comment) { if ($comment->isIdEqualTo($id)) { $comment->edit($parent ? $parent->id : null, $text); $this->updateComments($comments); return; } } throw new \DomainException('Comment is not found.'); } public function activateComment($id): void { $comments = $this->blogComments; foreach ($comments as $comment) { if ($comment->isIdEqualTo($id)) { $comment->activate(); $this->updateComments($comments); return; } } throw new \DomainException('Comment is not found.'); } public function removeComment($id): void { $comments = $this->blogComments; foreach ($comments as $i => $comment) { if ($comment->isIdEqualTo($id)) { if ($this->hasChildren($comment->id)) { $comment->draft(); } else { unset($comments[$i]); } $this->updateComments($comments); return; } } throw new \DomainException('Comment is not found.'); } public function getComment($id): BlogComment { foreach ($this->blogComments as $comment) { if ($comment->isIdEqualTo($id)) { return $comment; } } throw new \DomainException('Comment is not found.'); } private function hasChildren($id): bool { foreach ($this->blogComments as $comment) { if ($comment->isChildOf($id)) { return true; } } return false; } private function updateComments(array $comments): void { $this->blogComments = $comments; $this->comments_count = count(array_filter($comments, function (BlogComment $comment) { return $comment->isActive(); })); } ###################################### public function getBlogComments(): ActiveQuery { return $this->hasMany(BlogComment::class, ['post_id' => 'id']); } public function getBlogTagAssignments(): ActiveQuery { return $this->hasMany(BlogTagAssignment::class, ['post_id' => 'id']); } public function getTags(): ActiveQuery { return $this->hasMany(BlogTag::class, ['id' => 'tag_id'])->viaTable('blog_tag_assignments', ['post_id' => 'id']); } public function getCategory(): ActiveQuery { return $this->hasOne(BlogCategory::class, ['id' => 'category_id']); } ###################################### public function behaviors(): array { return [ TimestampBehavior::class, MetaBehavior::class, [ 'class' => SaveRelationsBehavior::class, 'relations' => ['blogTagAssignments', 'blogComments'], ], [ // todo Image Sizes to settings or theme settings 'class' => ImageUploadBehavior::class, 'attribute' => 'image', 'createThumbsOnRequest' => true, //'filePath' => $this::FILE_ORIGINAL_PATH . '/[[id]].[[extension]]', 'filePath' => '@staticRoot/origin/posts/[[id]].[[extension]]', 'fileUrl' => '@static/origin/posts/[[id]].[[extension]]', 'thumbPath' => '@staticRoot/cache/posts/[[profile]]_[[id]].[[extension]]', 'thumbUrl' => '@static/cache/posts/[[profile]]_[[id]].[[extension]]', 'thumbs' => [ 'blog_list' => ['width' => 750, 'height' => 300, 'resizeUp' => true], 'blog_post' => ['width' => 900, 'height' => 300], 'admin' => ['width' => 60, 'height' => 60], 'thumb' => ['width' => 150, 'height' => 150], 'list' => ['width' => 200, 'height' => 200], 'home_slider' => ['width' => 369, 'height' => 343], '94_94' => ['width' => 94, 'height' => 94], '368_287' => ['width' => 368, 'height' => 287], '370_325' => ['width' => 370, 'height' => 325], '683_407' => ['width' => 683, 'height' => 407], 'thumb_gallery_view' => ['width' => 300, 'height' => 170], //'widget_list' => ['width' => 228, 'height' => 228], //'origin' => ['processor' => [new WaterMarker(1024, 768, '@frontend/web/image/logo.png'), 'process']], 'origin' => ['width' => 1024, 'height' => 768], ], ], ]; } public function transactions(): array { return [ self::SCENARIO_DEFAULT => self::OP_ALL, ]; } public static function find(): BlogPostQuery { return new BlogPostQuery(static::class); } }