Drupal 8:自定义评论排序

Drupal 8 的评论系统具有线程化功能,以便用户可以直接回复其他用户的评论并创建对话线程。我一直觉得这很难使用和阅读,所以我想在我设置这个网站时把它关掉。我遇到的唯一问题是我可以关闭线程,但无法更改评论的顺序。

Drupal 8 中默认的注释排序是按线程排序的。这意味着即使您关闭线程,评论也始终按线程顺序显示。Drupal 使用 CommentDefaultFormatter 类来显示注释并包含这行代码。

$comments = $this->storage->loadThread($entity, $field_name, $mode, $comments_per_page, $this->getSetting('pager_id'));

没有选项可以将其更改loadThread()为其他内容,这意味着只要 Drupal 使用此类来显示注释,它将始终使用此方法。

要覆盖它,我们可以使用自定义 FieldFormatter 插件并使用自定义格式化程序重新排序注释。

在自定义模块中,在 src/Plugin/Field/FieldFormatter/CustomCommentFormatter.php 创建一个类。这是允许我们提供我们自己的自定义评论排序的插件。这个类只是扩展了 CommentDefaultFormatter 类(这是我们想要覆盖的类),所以我们只需要包含我们需要覆盖的方法。

<?php
 
namespace Drupal\custom_comment_module\Plugin\Field\FieldFormatter;
 
use Drupal\comment\Plugin\Field\FieldFormatter\CommentDefaultFormatter;
 
/**
 * Provides a custom comment formatter to order comments by date.
 *
 * @FieldFormatter(
 *   id = "comment_orderbydate",
 *   module = "comment",
 *   label = @Translation("Custom comment list"),
 *   field_types = {
 *     "comment"
 *   },
 *   quickedit = {
 *     "editor" = "disabled"
 *   }
 * )
 */
class CustomCommentFormatter extends CommentDefaultFormatter {
 
}

由于在 Drupal 中检索和排序评论的方式,我们需要覆盖 CommentStorage 类以更改评论的加载方式。这可以通过使用 hook_entity_type_alter()更改 Comment 实体的存储处理程序来实现。这将通过以下方式完成。

/**
 * Implements hook_entity_type_alter().
 */
function custom_comment_entity_type_alter(array &$entity_types) {
  $entity_types['page']->setHandlerClass('storage', CustomCommentStorage::class);
}

另一种(也许更简单?)的方法是loadThread()用一些能以我们想要的方式加载注释的东西替换类中的方法。为此,我首先需要修改 CustomCommentFormatter 类,以便通过依赖注入加载到数据库中。虽然看起来我在这里写了很多代码,但实际上只是添加了数据库处理程序,所有其他注入的依赖项已经被 CommentDefaultFormatter 类使用,因此需要包含在内。

<?php
 
namespace Drupal\custom_comment_module\Plugin\Field\FieldFormatter;
 
use Drupal\comment\Plugin\Field\FieldFormatter\CommentDefaultFormatter;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\comment\CommentInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityFormBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
 
/**
 * Provides a custom comment formatter to order comments by date.
 *
 * @FieldFormatter(
 *   id = "comment_orderbydate",
 *   module = "comment",
 *   label = @Translation("Custom comment list"),
 *   field_types = {
 *     "comment"
 *   },
 *   quickedit = {
 *     "editor" = "disabled"
 *   }
 * )
 */
class CustomCommentFormatter extends CommentDefaultFormatter {
 
  /**
   * The entity form builder.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;
 
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $plugin_id,
      $plugin_definition,
      $configuration['field_definition'],
      $configuration['settings'],
      $configuration['label'],
      $configuration['view_mode'],
      $configuration['third_party_settings'],
      $container->get('current_user'),
      $container->get('entity.manager'),
      $container->get('entity.form_builder'),
      $container->get('current_route_match'),
      $container->get('database')
    );
  }
 
  /**
   * CustomCommentFormatter constructor.
   *
   * @param string $plugin_id
   *   The plugin_id for the formatter.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The definition of the field to which the formatter is associated.
   * @param array $settings
   *   The formatter settings.
   * @param string $label
   *   The formatter label display setting.
   * @param string $view_mode
   *   The view mode.
   * @param array $third_party_settings
   *   Third party settings.
   * @param \Drupal\Core\Session\AccountInterface $current_user
   *   The current user.
   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
   *   The entity manager
   * @param \Drupal\Core\Entity\EntityFormBuilderInterface $entity_form_builder
   *   The entity form builder.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match object.
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection to be used.
   */
  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, AccountInterface $current_user, EntityManagerInterface $entity_manager, EntityFormBuilderInterface $entity_form_builder, RouteMatchInterface $route_match, Connection $database) {
    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings, $current_user, $entity_manager, $entity_form_builder, $route_match);
    $this->database = $database;
  }
}

有了这个,我们就可以添加一个自定义loadComments()方法。此方法与 方法非常相似loadThread(),但在这种情况下,它按日期加载评论,按升序排列。 

  /**
   * Retrieves comments for a thread, sorted in an order suitable for display.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity whose comment(s) needs rendering.
   * @param string $field_name
   *   The field_name whose comment(s) needs rendering.
   * @param int $mode
   *   The comment display mode: CommentManagerInterface::COMMENT_MODE_FLAT or
   *   CommentManagerInterface::COMMENT_MODE_THREADED.
   * @param int $comments_per_page
   *   (optional) The amount of comments to display per page.
   *   Defaults to 0, which means show all comments.
   * @param int $pager_id
   *   (optional) Pager id to use in case of multiple pagers on the one page.
   *   Defaults to 0; is only used when $comments_per_page is greater than zero.
   *
   * @return array
   *   Ordered array of comment objects, keyed by comment id.
   */
  public function loadComments(EntityInterface $entity, $field_name, $mode, $comments_per_page = 0, $pager_id = 0) {
    $query = $this->database->select('comment_field_data', 'c');
    $query->addField('c', 'cid');
    $query
      ->condition('c.entity_id', $entity->id())
      ->condition('c.entity_type', $entity->getEntityTypeId())
      ->condition('c.field_name', $field_name)
      ->condition('c.default_langcode', 1)
      ->addTag('entity_access')
      ->addTag('comment_filter')
      ->addMetaData('base_table', 'comment')
      ->addMetaData('entity', $entity)
      ->addMetaData('field_name', $field_name);
 
    if ($comments_per_page) {
      $query = $query->extend('Drupal\Core\Database\Query\PagerSelectExtender')
        ->limit($comments_per_page);
      if ($pager_id) {
        $query->element($pager_id);
      }
 
      $count_query = $this->database->select('comment_field_data', 'c');
      $count_query->addExpression('COUNT(*)');
      $count_query
        ->condition('c.entity_id', $entity->id())
        ->condition('c.entity_type', $entity->getEntityTypeId())
        ->condition('c.field_name', $field_name)
        ->condition('c.default_langcode', 1)
        ->addTag('entity_access')
        ->addTag('comment_filter')
        ->addMetaData('base_table', 'comment')
        ->addMetaData('entity', $entity)
        ->addMetaData('field_name', $field_name);
      $query->setCountQuery($count_query);
    }
 
    if (!$this->currentUser->hasPermission('administer comments')) {
      $query->condition('c.status', CommentInterface::PUBLISHED);
      if ($comments_per_page) {
        $count_query->condition('c.status', CommentInterface::PUBLISHED);
      }
    }
 
    $query->orderBy('c.created', 'ASC');
 
    $cids = $query->execute()->fetchCol();
 
    $comments = [];
    if ($cids) {
      $comments = $this->storage->loadMultiple($cids);
    }
 
    return $comments;
  }

现在所需要做的就是将viewElements()方法更改为 使用新loadComments()方法而不是loadThread().

$comments = $this->loadComments($entity, $field_name, $mode, $comments_per_page, $this->getSetting('pager_id'));

激活模块后,我们现在可以从管理显示管理区域中选择格式化程序。这可以在启用评论的内容类型的字段管理区域中找到。

保存表单后,评论将按日期顺序排列。