diff --git a/behaviors/CommentBehavior.php b/behaviors/CommentBehavior.php new file mode 100644 index 0000000..66641fd --- /dev/null +++ b/behaviors/CommentBehavior.php @@ -0,0 +1,207 @@ +cacheRating) { + if (empty( $this->cacheModelName ) || !is_string($this->cacheModelName)) { + throw new InvalidConfigException( + 'To use rating cache you must set $cacheModelName where to store it' + ); + } + $this->setCacheModel( + \Yii::createObject( + [ + 'class' => $this->cacheModelName, + ] + ) + ); + } + parent::attach($owner); + } + + /** + * Get fully-classified name of class to hold rating cache + * + * @return string + */ + public function getCacheModelName():string + { + return $this->cacheModelName; + } + + /** + * Set fully-classified name of class to hold rating cache + * + * @param string $value + */ + public function setCacheModelName(string $value) + { + $this->cacheModelName = $value; + } + + /** + * Get model to hold rating cache + * + * @return \artweb\artbox\comment\models\interfaces\RatingCacheInterface + */ + public function getCacheModel():RatingCacheInterface + { + return $this->cacheModel; + } + + /** + * Set model to hold cache + * + * @param \artweb\artbox\comment\models\interfaces\RatingCacheInterface|null $value + */ + private function setCacheModel(RatingCacheInterface $value = null) + { + $this->cacheModel = $value; + } + + /** + * Whether cache rating or not + * + * @return bool + */ + public function getCacheRating(): bool + { + return $this->cacheRating; + } + + /** + * Set whether to cache rating or not + * + * @param bool $value + */ + public function setCacheRating(bool $value) + { + $this->cacheRating = $value; + } + + /** + * Get query to get all comments for current $owner model + * + * @return \yii\db\ActiveQuery + */ + public function getComments(): ActiveQuery + { + /** + * @var ActiveRecord $owner + */ + $owner = $this->owner; + $pk = $owner->primaryKey()[ 0 ]; + $query = $owner->hasMany(CommentModel::className(), [ 'entity_id' => $pk ]) + ->where( + [ + 'artbox_comment.entity' => $owner::className(), + 'artbox_comment.status' => CommentModel::STATUS_ACTIVE, + 'artbox_comment.artbox_comment_pid' => null, + ] + ); + return $query; + } + + /** + * Get query to get average rating for current $owner model if it cached + * + * @return \yii\db\ActiveQuery + */ + public function getAverageRating(): ActiveQuery + { + /** + * @var ActiveRecord $owner + */ + $owner = $this->owner; + $pk = $owner->primaryKey()[ 0 ]; + $query = $owner->hasOne($this->cacheModelName, [ $this->cacheModel->getLinkAttribute() => $pk ]); + return $query; + } + + /** + * Recalculate cache for current $owner model + * + * @return bool + */ + public function recalculateRating(): bool + { + /** + * @var RatingCacheInterface $averageRating + */ + $average = $this->getComments() + ->joinWith('rating') + ->select([ 'average' => 'avg(artbox_comment_rating.value)::float' ]) + ->scalar(); + if (!$average) { + $average = 0; + } + $averageRating = $this->getAverageRating() + ->one(); + if (!empty( $averageRating )) { + $averageRating->setValue($average); + } else { + /** + * @var ActiveRecord $owner + * @var RatingCacheInterface $averageRating + */ + $owner = $this->owner; + $pk = $owner->primaryKey()[ 0 ]; + $averageRating = \Yii::createObject( + [ + 'class' => $this->cacheModelName, + $this->cacheModel->getLinkAttribute() => $this->owner->$pk, + ] + ); + $averageRating->setValue($average); + } + if ($averageRating->save()) { + return true; + } else { + return false; + } + } + } + \ No newline at end of file diff --git a/models/interfaces/RatingCacheInterface.php b/models/interfaces/RatingCacheInterface.php new file mode 100644 index 0000000..870f1a9 --- /dev/null +++ b/models/interfaces/RatingCacheInterface.php @@ -0,0 +1,31 @@ +