diff --git a/common/config/main.php b/common/config/main.php index bd1feec..071f0df 100755 --- a/common/config/main.php +++ b/common/config/main.php @@ -24,7 +24,10 @@ 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field ) 'targetMinPixel' => 200 // Target image minimum pixel size ] - ] + ], + 'artbox-comment' => [ + 'class' => \common\modules\comment\Controller::className(), + ], ], 'modules' => [ diff --git a/common/models/Blog.php b/common/models/Blog.php index f435e20..aa79dae 100644 --- a/common/models/Blog.php +++ b/common/models/Blog.php @@ -87,8 +87,6 @@ return date('Y-m-d',strtotime($this->date_add)); } - - /** * @inheritdoc */ diff --git a/common/modules/comment/Controller.php b/common/modules/comment/Controller.php new file mode 100644 index 0000000..d0ce56f --- /dev/null +++ b/common/modules/comment/Controller.php @@ -0,0 +1,96 @@ + [ + 'class' => \yii\filters\VerbFilter::className(), + 'actions' => [ + '*' => ['post'], + ], + ], + ]; + } + + public function actionDelete() + { + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + $post = \Yii::$app->request->post('Comment'); + if(!empty($post['comment_id'])) { + if($model = \common\modules\comment\models\Comment::findOne($post['comment_id'])) { + /** + * @var \common\modules\comment\models\Comment $model + */ + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST; + if($model->deleteComment()) { + \Yii::$app->response->data = ['text' => 'Comment marked as deleted and will be check by administrators']; + } else { + \Yii::$app->response->data = ['error' => $model->hasErrors('comment_id')?$model->getFirstError('comment_id'):'Cannot delete message']; + } + }else { + \Yii::$app->response->data = ['error' => 'Comment not found']; + }; + } else { + \Yii::$app->response->data = ['error' => 'Missing comment_id']; + } + \Yii::$app->response->send(); + } + + public function actionUpdate() + { + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + $post = \Yii::$app->request->post(); + if(!empty($post['Comment']['comment_id'])) { + if($model = \common\modules\comment\models\Comment::findOne($post['Comment']['comment_id'])) { + /** + * @var \common\modules\comment\models\Comment $model + */ + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST; + $model->load($post); + if(empty($post['Comment']['comment_pid'])) { + $model->comment_pid = null; + } + if($model->updateComment()) { + \Yii::$app->response->data = ['text' => 'Comment successfully updated']; + } else { + \Yii::$app->response->data = ['error' => $model->hasErrors()?$model->getFirstErrors():'Cannot update message']; + } + }else { + \Yii::$app->response->data = ['error' => 'Comment not found']; + }; + } else { + \Yii::$app->response->data = ['error' => 'Missing comment_id']; + } + \Yii::$app->response->send(); + } + + public function actionForm() + { + $post = \Yii::$app->request->post('Comment'); + if(!empty($post['comment_id'])) { + $model = \common\modules\comment\models\Comment::find()->where(['comment_id' => $post['comment_id']])->with('parent', 'author')->one(); + if($model) { + /** + * @var \common\modules\comment\models\Comment $model + */ + $model->scenario = is_int(\Yii::$app->user->getId()) ? \common\modules\comment\models\Comment::SCENARIO_USER : \common\modules\comment\models\Comment::SCENARIO_GUEST; + if($model->checkUpdate()) { + return $this->renderAjax('@common/modules/comment/views/comment_form', [ + 'model' => $model, + ]); + } else { + \Yii::$app->response->data = ['error' => 'You are not able to update this comment']; + } + }else { + \Yii::$app->response->data = ['error' => 'Comment not found']; + }; + } else { + \Yii::$app->response->data = ['error' => 'Missing comment_id']; + } + \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + \Yii::$app->response->send(); + } + } \ No newline at end of file diff --git a/common/modules/comment/Permissions.php b/common/modules/comment/Permissions.php index 49b5aec..965f0f4 100644 --- a/common/modules/comment/Permissions.php +++ b/common/modules/comment/Permissions.php @@ -8,5 +8,5 @@ const UPDATE = 'artbox_comment.update'; const DELETE = 'artbox_comment.delete'; const UPDATE_OWN = 'artbox_comment.update_own'; - const DELETE_OWN = 'artbox_comment.delete.own'; + const DELETE_OWN = 'artbox_comment.delete_own'; } \ No newline at end of file diff --git a/common/modules/comment/assets/CommentAsset.php b/common/modules/comment/assets/CommentAsset.php new file mode 100644 index 0000000..edf61a8 --- /dev/null +++ b/common/modules/comment/assets/CommentAsset.php @@ -0,0 +1,21 @@ + 1, + ], + [ + [ 'comment_pid' ], + 'exist', + 'targetAttribute' => 'comment_id', + 'filter' => [ + 'entity' => $this->entity, + ], + ], ]; } public function scenarios() { return [ - self::SCENARIO_GUEST => ['user_name', 'user_email', 'text'], - self::SCENARIO_USER => ['text'], + self::SCENARIO_GUEST => [ + 'user_name', + 'user_email', + 'text', + 'comment_pid', + ], + self::SCENARIO_USER => [ + 'text', + 'comment_pid', + ], + ]; + } + + /** + * @inheritdoc + */ + public function behaviors() + { + return [ + [ + 'class' => \yii\behaviors\TimestampBehavior::className(), + 'createdAtAttribute' => 'date_add', + 'updatedAtAttribute' => 'date_update', + 'value' => new \yii\db\Expression('NOW()'), + ], ]; } @@ -55,52 +114,119 @@ public function attributeLabels() { return [ - 'text' => \Yii::t('app', 'Комментарий'), - 'user_name' => \Yii::t('app', 'Имя'), + 'text' => \Yii::t('app', 'Комментарий'), + 'user_name' => \Yii::t('app', 'Имя'), 'user_email' => \Yii::t('app', 'Email'), ]; } - public function getGuestComment($entity) + public function getGuestComment() + { + return $this->guestComment; + } + + public function setGuestComment($value) { - return true; + $this->guestComment = $value; } public function getComments($entity) { - return $this->find()->where(['entity' => $this->entity]); + return $this->find() + ->where([ + 'entity' => $this->entity, + 'status' => 1, + ]); } - public function postComment($data) + public function postComment() { - if($this->load($data) && $this->insert($data)) { - $this->clearSafe(); - return true; + if($this->checkCreate()) { + if($this->insert()) { + $this->clearSafe(); + return true; + } else { + return false; + } } else { + $this->addError('comment_id', 'You can`t post comment here'); return false; } } - public function updateComment($comment_id) + public function updateComment() { - // TODO: Implement updateComment() method. + if($this->checkUpdate()) { + if(empty( $this->comment_id )) { + $this->addError('comment_id', 'Comment ID not found'); + return false; + } else { + if($this->update()) { + $this->clearSafe(); + return true; + } else { + return false; + } + } + } else { + $this->addError('comment_id', 'You can`t update this post'); + return false; + } } - public function deleteComment($comment_id) + public function deleteComment() { - // TODO: Implement deleteComment() method. + if($this->checkDelete()) { + if(empty( $this->comment_id )) { + $this->addError('comment_id', 'Comment ID not found'); + return false; + } else { + if($this->status == self::STATUS_DELETED) { + return false; + } + $this->status = self::STATUS_DELETED; + if($this->update()) { + $this->clearSafe(); + return true; + } else { + return false; + } + } + } else { + $this->addError('comment_id', 'You can`t delete this post'); + return false; + } } - public function checkCreate($entity) + public function checkCreate() { - if($this->getGuestComment($entity)) { + if($this->getGuestComment()) { return true; } else { - return \Yii::$app->user->can(\common\modules\comment\Permissions::CREATE, ['entity' => $entity]); + return \Yii::$app->user->can(\common\modules\comment\Permissions::CREATE, [ 'entity' => $this->entity ]); } } - protected function clearSafe($setNew = true) { + public function checkUpdate() + { + if($this->scenario == self::SCENARIO_GUEST) { + return false; + } else { + return \Yii::$app->user->can(\common\modules\comment\Permissions::UPDATE, [ 'entity' => $this->entity ]) || \Yii::$app->user->can(\common\modules\comment\Permissions::UPDATE_OWN, [ 'entity' => $this->entity ]); + } + } + + public function checkDelete() + { + if($this->scenario == self::SCENARIO_GUEST) { + return false; + } else { + return \Yii::$app->user->can(\common\modules\comment\Permissions::DELETE, [ 'entity' => $this->entity ]) || \Yii::$app->user->can(\common\modules\comment\Permissions::DELETE_OWN, [ 'entity' => $this->entity ]); + } + } + + protected function clearSafe($setNew = true) + { $safe = $this->safeAttributes(); $count = count($safe); $values = array_fill(0, $count, NULL); @@ -109,4 +235,56 @@ $this->setIsNewRecord($setNew); } - } \ No newline at end of file + public function getParent() + { + return $this->hasOne(self::className(), [ 'comment_id' => 'comment_pid' ]); + } + + public function getAuthor() + { + // if($this->user_id != NULL) { + return $this->hasOne(\common\models\User::className(), [ 'id' => 'user_id' ]); + // } else { + // return ['firstname' => $this->user_name, 'email' => $this->user_email]; + // } + } + + public function checkRating() + { + $rating = $this->hasOne(\common\modules\comment\models\Rating::className(), [ 'entity' => 'entityId' ]) + ->one(); + if(!$rating instanceof \common\modules\comment\models\Rating) { + $rating = new \common\modules\comment\models\Rating([ + 'entity' => $this->entityId, + 'user_id' => $this->user_id, + ]); + $rating->save(); + } + } + + public function getRating() + { + $this->checkRating(); + return $this->hasOne(\common\modules\comment\models\Rating::className(), [ 'entity' => 'entityId' ]); + } + + public function hasRating($return = true) + { + $rating = $this->hasOne(\common\modules\comment\models\Rating::className(), [ 'entity' => 'entityId' ]) + ->andWhere([ + 'not', + [ 'value' => NULL ], + ]) + ->one(); + if($return) { + return $rating; + } else { + return $rating ? true : false; + } + } + + public function getEntityId() + { + return $this->formName() . '-' . $this->getPrimaryKey(); + } + } diff --git a/common/modules/comment/models/Rating.php b/common/modules/comment/models/Rating.php new file mode 100644 index 0000000..cfda4e1 --- /dev/null +++ b/common/modules/comment/models/Rating.php @@ -0,0 +1,61 @@ + Yii::t('app', 'Rating ID'), + 'date_add' => Yii::t('app', 'Date Add'), + 'date_update' => Yii::t('app', 'Date Update'), + 'user_id' => Yii::t('app', 'User ID'), + 'entity' => Yii::t('app', 'Entity'), + 'value' => Yii::t('app', 'Value'), + ]; + } + + /** + * @return \yii\db\ActiveQuery + */ + public function getUser() + { + return $this->hasOne(\common\models\User::className(), ['id' => 'user_id']); + } +} diff --git a/common/modules/comment/resources/comment.css b/common/modules/comment/resources/comment.css new file mode 100644 index 0000000..2577fa1 --- /dev/null +++ b/common/modules/comment/resources/comment.css @@ -0,0 +1,19 @@ +.artbox_comment_reply_author, .artbox_comment_update_reply { + position: relative; + width: 25%; +} +.artbox_comment_update_reply { + width: 25%; + float: none; +} +.artbox_comment_reply_author:after, .artbox_comment_update_reply:after { + content: ''; + background-image: url('delete-ico.png'); + display: block; + position: absolute; + right: -13px; + width: 13px; + height: 13px; + top: 0; + cursor: pointer; +} \ No newline at end of file diff --git a/common/modules/comment/resources/comment.js b/common/modules/comment/resources/comment.js new file mode 100644 index 0000000..f853007 --- /dev/null +++ b/common/modules/comment/resources/comment.js @@ -0,0 +1,89 @@ +$(function() { + + $(document).on('click', '.artbox_comment_delete', function() { + var container = $(this).parents('.artbox_comment_container'); + var comment_id = $(container).data('comment_id'); + var form_name = $(container).data('form_name'); + if(confirm("Уверены, что хотите удалить комментарий?")) { + $.post( + '/artbox-comment/delete', + { + Comment: { + comment_id: comment_id + } + }, + function(data, textStatus, jqXHR) { + if(!data.error) { + $(container).after('
'+data.text+'
'); + $(container).remove(); + } else { + $(container).prepend('') + } + } + ); + } + }); + + $(document).on('click', '.artbox_comment_reply', function() { + var container = $(this).parents('.artbox_comment_container').first(); + var comment_id = $(container).data('comment_id'); + var form_name = $(container).data('form_name'); + var author = $(container).find('.artbox_comment_author').first().text(); + var comment_form = $('.artbox_comment_form').first(); + var offset = $(comment_form).offset(); + var reply_block = $(comment_form).find('.artbox_comment_reply_block').first(); + $(reply_block).empty(); + $(reply_block).append(''); + $(reply_block).append(''); + $('html, body').animate({ + scrollTop: offset.top - 50, + }); + }); + + $(document).on('click', '.artbox_comment_reply_author', function() { + $(this).parents('.artbox_comment_reply_block').first().empty(); + }); + + $(document).on('click', '.artbox_comment_update', function() { + $(this).removeClass('artbox_comment_update'); + $(this).text('Сохранить'); + $(this).addClass('artbox_comment_update_submit'); + var container = $(this).parents('.artbox_comment_container').first(); + var comment_id = $(container).data('comment_id'); + var form_name = $(container).data('form_name'); + var text = $(container).find('.artbox_comment_text'); + var object = {}; + object[form_name] = {comment_id: comment_id}; + $.post( + '/artbox-comment/form', + object, + function(data, textStatus, jqXHR) { + $(text).hide(); + $(text).after( + '{success}, {form}, {list}
+ * to render particular parts. You are also able to use common HTML here.
+ */
public $template = "{success}\n{form}\n{list}";
- public $options = [];
+ /**
+ * @var array Widget options
+ */
+ public $options = [ ];
/**
- * @var \yii\data\DataProviderInterface
+ * @var \yii\data\DataProviderInterface Data provider of comments
*/
public $dataProvider;
@@ -75,16 +112,20 @@
public function init()
{
parent::init();
+ \common\modules\comment\assets\CommentAsset::register($this->view);
if(is_string($this->comment_class)) {
$this->comment_class = new $this->comment_class($this->class_options);
- } elseif(!is_object($this->comment_class)) {
- throw new \yii\base\InvalidConfigException(__CLASS__.'->comment_class must be defined as string or object.');
+ } else {
+ throw new \yii\base\InvalidConfigException(__CLASS__ . '->comment_class must be defined as object full class name string.');
+ }
+ if(!empty( $this->rating_class ) && is_string($this->rating_class)) {
+ $this->rating_class = new $this->rating_class($this->rating_options);
+ } elseif(!empty( $this->rating_class )) {
+ throw new \yii\base\InvalidConfigException(__CLASS__ . '->rating_class must be defined as object full class name string.');
}
$this->comment_class->entity = $this->entity;
$this->createDataProvider();
- if($this->comment_class->checkCreate($this->entity)) {
- $this->handleCreate();
- }
+ $this->process();
ob_start();
}
@@ -99,62 +140,67 @@
return $this->renderWidget();
}
- public function createParts() {
+ public function createParts()
+ {
if($this->display_comment_success && $this->isSuccess) {
$tag = ArrayHelper::remove($this->success_options, 'tag', 'div');
- if(is_callable($this->success_options['content'])) {
+ if(is_callable($this->success_options[ 'content' ])) {
$result = call_user_func(ArrayHelper::remove($this->success_options, 'content'), $this->success_text);
- } elseif($this->success_options['content'] != NULL) {
+ } elseif($this->success_options[ 'content' ] != NULL) {
$result = Html::encode(ArrayHelper::remove($this->success_options, 'content', $this->success_text));
} else {
$result = Html::encode($this->success_text);
}
- $this->parts['success'] = Html::tag($tag, $result, $this->success_options);
- unset($tag, $result);
+ $this->parts[ 'success' ] = Html::tag($tag, $result, $this->success_options);
+ unset( $tag, $result );
}
if($this->display_comment_list) {
$tag = ArrayHelper::remove($this->list_options, 'tag', 'div');
$view = ArrayHelper::remove($this->list_options, 'view');
- $this->parts['list'] = Html::tag($tag, $this->renderItems($view), $this->list_options);
+ $this->parts[ 'list' ] = Html::tag($tag, $this->renderItems($view), $this->list_options);
}
if($this->display_comment_form) {
$tag = ArrayHelper::remove($this->form_options, 'tag', 'div');
$view = ArrayHelper::remove($this->form_options, 'view');
- $this->parts['form'] = Html::tag($tag, $this->renderForm($view), $this->list_options);
+ $this->parts[ 'form' ] = Html::tag($tag, $this->renderForm($view), $this->form_options);
}
}
public function createDataProvider()
{
$this->dataProvider = new \yii\data\ActiveDataProvider([
- 'query' => $this->comment_class->getComments($this->entity),
+ 'query' => $this->comment_class->getComments($this->entity),
'pagination' => [
'pageSize' => 10,
],
]);
}
- public function renderItems($view) {
- if(empty($view)) {
+ public function renderItems($view)
+ {
+ if(empty( $view )) {
throw new \yii\base\InvalidConfigException("list_options[view] must be set");
}
- return $this->render($view, ['dataProvider' => $this->dataProvider]);
+ return $this->render($view, [ 'dataProvider' => $this->dataProvider ]);
}
- public function renderForm($view) {
- if(empty($view)) {
+ public function renderForm($view)
+ {
+ if(empty( $view )) {
throw new \yii\base\InvalidConfigException("form_options[view] must be set");
}
return $this->render($view, [
- 'model' => $this->comment_class,
- 'user' => \Yii::$app->user->identity,
+ 'model' => $this->comment_class,
+ 'rating' => $this->rating_class,
+ 'user' => \Yii::$app->user->identity,
'dataProvider' => $this->dataProvider,
]);
}
- public function renderWidget() {
+ public function renderWidget()
+ {
$template = $this->template;
$parts = $this->parts;
$options = $this->options;
@@ -165,11 +211,13 @@
return Html::tag($tag, $template, $options);
}
- public function handleCreate()
+ public function process()
{
$data = \Yii::$app->request->post();
- if($this->comment_class->postComment($data)) {
- $this->isSuccess = true;
- };
+ if($this->comment_class->load($data) && $this->comment_class->postComment()) {
+ if(is_object($this->rating_class) && $this->comment_class->rating->load($data) && $this->comment_class->rating->save()) {
+ $this->isSuccess = true;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/common/modules/comment/widgets/views/form-comment.php b/common/modules/comment/widgets/views/form-comment.php
index 1e3fe2b..9262ebc 100644
--- a/common/modules/comment/widgets/views/form-comment.php
+++ b/common/modules/comment/widgets/views/form-comment.php
@@ -1,8 +1,9 @@
Комментарии: = $dataProvider->totalCount ?>
-