vorst.ru - Статьи о задачах возникающих при создании сайта и их решении
Статьи помеченные comment

Модерация и вывод комментариев

Ответ на комментарии и рекурсивный вывод

На сайте оставили комментарий, вы ответили. Оппонент что-то еще уточнил, вы опять ответили. Цепочка из нескольких вопросов/ответов, которую нужно представить в виде лестницы.

Отступы можно выводить в обычном цикле, но если отступы формируются с помощью блочных элементов и css, то проще использовать рекурсию.


Модуль для управления блогом

Блог включает управление комментариями, пользователями, rbac

Новости, сообщения, описания - это все статьи, а статьи - это блог. Блог является важной составляющей любого сайта.

Блог настолько важен, что самая популярная CMS на планете WordPress - это блог.

Во фреймворке блог пишется самостоятельно или используется готовый модуль. Или сначала пишется самостоятельно, а потом переписывается как модуль.



Поиск



Модерация и вывод комментариев

Ответ на комментарии и рекурсивный вывод

На сайте оставили комментарий, вы ответили. Оппонент что-то еще уточнил, вы опять ответили. Цепочка из нескольких вопросов/ответов, которую нужно представить в виде лестницы.

Отступы можно выводить в обычном цикле, но если отступы формируются с помощью блочных элементов и css, то проще использовать рекурсию.


    Поделиться

Представьте минидиалог.

  • Подскажите, как организовать комментарии на сайте?
    • Есть варианты. Каковы ваши требования?
      • Необходимо, чтобы юзер мог оставить комментарий, который будет размещен после модерации.
  • Добрый день! У меня такая же проблема.
    • Можно использовать следующий алгоритм ... [Ответить]

В каждом мини-диалоге участвуют двое. Если кто-то еще оставляет комментарий, то это новый мини-диалог. Вклиниться в мини-диалог стороннему комментатору нельзя.

Нужно, чтобы человек мог оставить отзыв, который можно было бы разместить, после модерации. Допустим, что комментарии могут оставлять только авторизованные пользователи и только во frontend.

Вы администратор сайта и вы видите оставленный комментарий в backend. Вы отвечаете на комментарий.

У пользователя, оставившего комментарий, должен отобразиться ваш ответ во frontend и кнопка [Ответить].

При упомянутом ограничении, а именно - в диалоге участвуют только двое: администратор и комментатор, структура данных для хранения комментариев примерно следующая.

id integer
post_id integer
user_id integer
content text
status integer
last boolean
thread char(32)
created_at integer

Нить диалога

Каждый новый комментарий получает уникальное значение - код нити (thread). Ответный комментарий получает то же значение thread, что и начальный комментарий. Если отсортировать все комментарии с одинаковым значением thread по дате, то получим цепочку диалога.

content thread
Подскажите, как организовать комментарии на сайте? a1
Есть варианты. Каковы ваши требования? a1
Необходимо, чтобы юзер мог оставить комментарий, который будет размещен после модерации. a1
Добрый день! У меня такая же проблема. b2
Можно использовать следующий алгоритм ... b2

Вывод комментариев в backend

Вывод комментариев уступами можно выполнить с помощью стандартного Grid, если сохранить текущее значение thread и использовать его при выводе следующего комментария. Для сохранения используем внутреннюю переменную params класса yii\base\View.

<?= GridView::widget([
  'dataProvider' => $dataProvider,
  'filterModel' => $searchModel,
  'layout' => "{items}\n{summary}\n{pager}",
  'columns' => [
  ...
  [
    'attribute' => 'content',
    'value' => function($data) {
      // declare params for indention in a row,
      // using View class internal variable - params
      if(!isset($this->params['thread']))
        $this->params['thread'] = false;
      if($this->params['thread'] == $data->thread) 
        $this->params['indention'] .= '--';
      else {
        $this->params['thread'] = $data->thread;
        $this->params['indention'] = '';
      }
      return $this->params['indention'] . ' ' . $data->content;
    }
  ],
  ...

Вывод комментариев во frontend

Верстка во frontend, как правило, более изощренная и часто основана на bootstrap media object. Начинается вывод с frontend/views/post/view.php в котором где-то, после текста поста, присутствует следующий код:

<?php echo $this->render('_comments', [
  'post' => $model,
  'comments' => $model->comments,
]); ?>

Комментарии выводятся один за другим. Если у комментариев одинаковый thread, то нужно сделать отступ и напечатать текущий комментарий. И так далее, пока не изменится thread. Рекурсивно подобный процесс представить легче.

Рекурсия

Определим основной цикл вывода frontend/views/post/_comments.php. Как и в backend промежуточные переменные сохраняются во внутренней переменной params класса yii\base\View.

<?php
function close_thread($level) {
  while($level > 1) {
    $level--;
    echo '</div>';
  }
}
?>
<?php $i = 0; $this->params['comments'] = $comments; ?>
<ul class="media-list">
  <?php while($i < count($comments)): ?>
    <li class="media">    
    <?php echo $this->render('_comment', [
      'i' => $i, 
      'thread' => $comments[$i]->thread, 
      'level' => 0]); 
      $i = $this->params['comment_i'];
    ?>
    </li> <!-- .media / -->
  <?php endwhile; ?>
</ul>

При выводе текущего комментария frontend/views/post/_comment.php новый блок (отступ) выводится пока thread тот же, что и у предыдущего комментария. Если же thread изменился, то блоки закрываются.

<?php $comment = $this->params['comments'][$i]; ?>
<div class="media-left">
  <i class="fa fa-2x fa-user"></i>
</div>
<div class="media-body">
  <div class="media-content">
    <h4 class="media-heading"><?= $comment->author->name ?></h4>
    <div class="alert alert-info" role="alert"><?= $comment->content ?></div>
    <?php if($comment->canBeAnswered()): ?>
      <div class="text-right">
        <a href="#comment-area" data-comment-thread="<?= $comment->thread ?>" class="btn btn-info reply-btn">
          <?= \Yii::t('app', 'Reply') ?>
        </a>
      </div>
    <?php endif; ?>
  </div>
<?php 
$i++;  $this->params['comment_i'] = $i; 
if($i < count($this->params['comments'])) {
  $comment = $this->params['comments'][$i];
  if($thread == $comment->thread) {
    $level++;
    echo '<div class="media-body">';
      echo $this->render('_comment', 
        ['i' => $i, 'thread' => $thread, 'level' => $level]);
  } else
    close_thread($level);
} else {
  close_thread($level);
}
?>

Право на ответ

Метод canBeAnswered() модели Comment вызывается во frontend при определении права текущего пользователя отвечать на последний комментарий.

Пользователь имеет право ответить на комментарий, если:

  • Пользователь авторизован;
  • Пользователь является инициатором мини-диалога;
  • Это последний комментарий в мини-диалоге;
  • И последний комментарий принадлежит модератору.


public function canBeAnswered() {
  $countInThread = Comment::find()
    ->where(['thread' => $this->thread, 'user_id' => \Yii::$app->user->id])
    ->count();
  return !\Yii::$app->user->isGuest &&
    $this->last && // this is a last comment in a thread
    \Yii::$app->user->identity->group == User::GROUP_COMMENTATOR && // you are a commentator
    $this->user_id != \Yii::$app->user->id && // last comment not yours
    $countInThread > 0; // you begin this thread
}

Как это работает во frontend, можно посмотреть на сайте. О backend подробнее в расширении sergmoro1/yii2-blog-tools.

Заключение

Комментарии в расширении sergmoro1/yii2-blog-tools могут оставлять только зарегистрированные пользователи. Комментарии должны модерироваться администратором сайта. Диалог возможен только между пользователем и администратором сайта.

Оставить комментарий

Только авторизованные пользователи могут оставлять комментарии. Пожалуйста авторизуйтесь или пройдите регистрацию.