Commit 37949fe3 authored by alexpott's avatar alexpott

Issue #731724 by larowlan, andypost, dixon_, tsvenson: Convert comment...

Issue #731724 by larowlan, andypost, dixon_, tsvenson: Convert comment settings into a field to make them work with CMI and non-node entities.
parent fb091cd6
......@@ -234,8 +234,6 @@ class EntityType extends Plugin {
/**
* The prefix for the bundles of this entity type.
*
* For example, the comment bundle is prefixed with 'comment_node_'.
*
* @var string (optional)
*/
public $bundle_prefix;
......
/**
* @file
* Attaches comment behaviors to the entity form.
*/
(function ($) {
"use strict";
Drupal.behaviors.commentFieldsetSummaries = {
attach: function (context) {
var $context = $(context);
$context.find('fieldset.comment-entity-settings-form').drupalSetSummary(function (context) {
return Drupal.checkPlain($(context).find('.form-item-comment input:checked').next('label').text());
});
}
};
})(jQuery);
/**
* @file
* Attaches comment behaviors to the node form.
*/
(function ($) {
"use strict";
Drupal.behaviors.commentDetailsSummaries = {
attach: function (context) {
var $context = $(context);
$context.find('.comment-node-settings-form').drupalSetSummary(function (context) {
return Drupal.checkPlain($(context).find('.form-item-comment input:checked').next('label').text());
});
// Provide the summary for the node type form.
$context.find('.comment-node-type-settings-form').drupalSetSummary(function(context) {
var $context = $(context);
var vals = [];
// Default comment setting.
vals.push($context.find(".form-item-comment select option:selected").text());
// Threading.
var threading = $(context).find(".form-item-comment-default-mode input:checked").next('label').text();
if (threading) {
vals.push(threading);
}
// Comments per page.
var number = $context.find(".form-item-comment-default-per-page select option:selected").val();
vals.push(Drupal.t('@number comments per page', {'@number': number}));
return Drupal.checkPlain(vals.join(', '));
});
}
};
})(jQuery);
......@@ -84,41 +84,53 @@ function comment_admin_overview($form, &$form_state, $arg) {
$query = db_select('comment', 'c')
->extend('Drupal\Core\Database\Query\PagerSelectExtender')
->extend('Drupal\Core\Database\Query\TableSortExtender');
$query->join('node_field_data', 'n', 'n.nid = c.nid');
$query->addTag('node_access');
if (\Drupal::moduleHandler()->moduleExists('node')) {
// Special case to ensure node access works.
$query->leftJoin('node_field_data', 'n', "n.nid = c.entity_id AND c.entity_type = 'node'");
$query->addTag('node_access');
}
$result = $query
->fields('c', array('cid', 'nid', 'subject', 'name', 'changed'))
->fields('c', array('cid', 'subject', 'name', 'changed', 'entity_id', 'entity_type', 'field_id'))
->condition('c.status', $status)
->limit(50)
->orderByHeader($header)
->execute();
$nids = array();
$cids = array();
$entity_ids = array();
$entities = array();
// We collect a sorted list of node_titles during the query to attach to the
// comments later.
// We collect entities grouped by entity_type so we can load them and use
// their labels.
foreach ($result as $row) {
$nids[] = $row->nid;
$entity_ids[$row->entity_type][] = $row->entity_id;
$cids[] = $row->cid;
}
// Ensure all nodes are statically cached so that we do not have to load them
// individually when getting their labels below.
node_load_multiple($nids);
$comments = comment_load_multiple($cids);
// Ensure all entities are statically cached so that we do not have to load
// them individually when getting their labels below.
foreach ($entity_ids as $entity_type => $ids) {
$entities[$entity_type] = entity_load_multiple($entity_type, $ids);
}
$comments = entity_load_multiple('comment', $cids);
// Build a table listing the appropriate comments.
$options = array();
$destination = drupal_get_destination();
foreach ($comments as $comment) {
// Use the first entity label.
$entity = $entities[$comment->entity_type->value][$comment->entity_id->value];
$entity_uri = $entity->uri();
// Remove the first node title from the node_titles array and attach to
// the comment.
$node_title = $comment->nid->entity->label();
$username = array(
'#theme' => 'username',
'#account' => comment_prepare_author($comment),
);
$body = '';
if (!empty($comment->comment_body->value)) {
$body = $comment->comment_body->value;
}
$options[$comment->id()] = array(
'title' => array('data' => array('#title' => $comment->subject->value ?: $comment->id())),
'subject' => array(
......@@ -126,15 +138,17 @@ function comment_admin_overview($form, &$form_state, $arg) {
'#type' => 'link',
'#title' => $comment->subject->value,
'#href' => 'comment/' . $comment->id(),
'#options' => array('attributes' => array('title' => truncate_utf8($comment->comment_body->value, 128)), 'fragment' => 'comment-' . $comment->id()),
'#options' => array('attributes' => array('title' => truncate_utf8($body, 128)), 'fragment' => 'comment-' . $comment->id()),
),
),
'author' => drupal_render($username),
'posted_in' => array(
'data' => array(
'#type' => 'link',
'#title' => $node_title,
'#href' => 'node/' . $comment->nid->target_id,
'#title' => $entity->label(),
'#href' => $entity_uri['path'],
'#options' => $entity_uri['options'],
'#access' => $entity->access('view'),
),
),
'changed' => format_date($comment->changed->value, 'short'),
......
......@@ -34,7 +34,9 @@ function hook_comment_presave(Drupal\comment\Comment $comment) {
*/
function hook_comment_insert(Drupal\comment\Comment $comment) {
// Reindex the node when comments are added.
node_reindex_node_search($comment->nid->target_id);
if ($comment->entity_type->value == 'node') {
node_reindex_node_search($comment->entity_id->value);
}
}
/**
......@@ -45,7 +47,9 @@ function hook_comment_insert(Drupal\comment\Comment $comment) {
*/
function hook_comment_update(Drupal\comment\Comment $comment) {
// Reindex the node when comments are updated.
node_reindex_node_search($comment->nid->target_id);
if ($comment->entity_type->value == 'node') {
node_reindex_node_search($comment->entity_id->value);
}
}
/**
......
......@@ -6,6 +6,5 @@ version: VERSION
core: 8.x
dependencies:
- datetime
- node
- text
configure: admin/content/comment
This diff is collapsed.
This diff is collapsed.
......@@ -46,12 +46,13 @@ comment.confirm_delete:
_entity_access: 'comment.delete'
comment.reply:
path: 'comment/reply/{node}/{pid}'
path: 'comment/reply/{entity_type}/{entity_id}/{field_name}/{pid}'
defaults:
_content: '\Drupal\comment\Controller\CommentController::getReplyForm'
_title: 'Add new comment'
pid: ~
requirements:
_entity_access: 'node.view'
_access: 'TRUE'
comment.new_comments_node_links:
path: '/comments/render_new_comments_node_links'
......@@ -59,3 +60,18 @@ comment.new_comments_node_links:
_controller: '\Drupal\comment\Controller\CommentController::renderNewCommentsNodeLinks'
requirements:
_permission: 'access content'
comment.bundle_list:
path: '/admin/structure/comments'
defaults:
_content: 'Drupal\comment\Controller\AdminController::overviewBundles'
requirements:
_permission: 'administer comments'
comment.bundle:
path: '/admin/structure/comments/manage/{field_name}'
defaults:
_content: 'Drupal\comment\Controller\AdminController::bundleInfo'
_title_callback: 'Drupal\comment\Controller\AdminController::bundleTitle'
requirements:
_access: 'FALSE'
......@@ -3,4 +3,14 @@ services:
class: Drupal\comment\CommentBreadcrumbBuilder
tags:
- { name: breadcrumb_builder, priority: 100 }
arguments: ['@string_translation']
arguments: ['@string_translation', '@entity.manager']
comment.subscriber:
class: Drupal\comment\Routing\RouteSubscriber
arguments: ['@module_handler']
tags:
- { name: event_subscriber }
comment.manager:
class: Drupal\comment\CommentManager
arguments: ['@field.info', '@entity.manager']
......@@ -15,14 +15,14 @@ function comment_token_info() {
'needs-data' => 'comment',
);
// Comment-related tokens for nodes
$node['comment-count'] = array(
// @todo Make this work per field. See http://drupal.org/node/2031903
$entity['comment-count'] = array(
'name' => t("Comment count"),
'description' => t("The number of comments posted on a node."),
'description' => t("The number of comments posted on an entity."),
);
$node['comment-count-new'] = array(
$entity['comment-count-new'] = array(
'name' => t("New comment count"),
'description' => t("The number of comments posted on a node since the reader last viewed it."),
'description' => t("The number of comments posted on an entity since the reader last viewed it."),
);
// Core comment tokens
......@@ -79,9 +79,16 @@ function comment_token_info() {
'description' => t("The comment's parent, if comment threading is active."),
'type' => 'comment',
);
$comment['entity'] = array(
'name' => t("Entity"),
'description' => t("The entity the comment was posted to."),
'type' => 'entity',
);
// Support legacy comment node tokens, since tokes are embedded in user data
// and can't be upgraded directly.
$comment['node'] = array(
'name' => t("Node"),
'description' => t("The node the comment was posted to."),
'description' => t("DEPRECATED: The node the comment was posted to."),
'type' => 'node',
);
$comment['author'] = array(
......@@ -93,8 +100,10 @@ function comment_token_info() {
return array(
'types' => array('comment' => $type),
'tokens' => array(
'node' => $node,
'entity' => $entity,
'comment' => $comment,
// Support deprecated node tokens.
'node' => $entity,
),
);
}
......@@ -177,8 +186,8 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
case 'parent':
if (!empty($comment->pid->target_id)) {
$parent = comment_load($comment->pid->target_id);
$replacements[$original] = $sanitize ? filter_xss($parent->subject) : $parent->subject;
$parent = entity_load('comment', $comment->pid->target_id);
$replacements[$original] = $sanitize ? filter_xss($parent->subject->value) : $parent->subject->value;
}
break;
......@@ -190,17 +199,36 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
$replacements[$original] = format_date($comment->changed->value, 'medium', '', NULL, $langcode);
break;
case 'node':
$node = $comment->nid->entity;
$title = $node->label();
case 'entity':
$entity = entity_load($comment->entity_type->value, $comment->entity_id->value);
$title = $entity->label();
$replacements[$original] = $sanitize ? filter_xss($title) : $title;
break;
case 'node':
// Support legacy comment node tokens, since tokes are embedded in
// user data and can't be upgraded directly.
// @todo Remove in Drupal 9, see https://drupal.org/node/2031901.
if ($comment->entity_type->value == 'node') {
$entity = entity_load($comment->entity_type->value, $comment->entity_id->value);
$title = $entity->label();
$replacements[$original] = $sanitize ? filter_xss($title) : $title;
}
else {
$replacements[$original] = NULL;
}
break;
}
}
// Chained token relationships.
if ($node_tokens = $token_service->findwithPrefix($tokens, 'node')) {
$node = $comment->nid->entity;
if ($entity_tokens = $token_service->findwithPrefix($tokens, 'entity')) {
$entity = entity_load($comment->entity_type->value, $comment->entity_id->value);
$replacements += $token_service->generate($comment->entity_type->value, $entity_tokens, array($comment->entity_type->value => $entity), $options);
}
if (($node_tokens = $token_service->findwithPrefix($tokens, 'node')) && $comment->entity_type->value == 'node') {
$node = entity_load($comment->entity_type->value, $comment->entity_id->value);
$replacements += $token_service->generate('node', $node_tokens, array('node' => $node), $options);
}
......@@ -220,17 +248,25 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
$replacements += $token_service->generate('user', $author_tokens, array('user' => $account), $options);
}
}
elseif ($type == 'node' & !empty($data['node'])) {
$node = $data['node'];
elseif (($type == 'entity' & !empty($data['entity'])) ||
($type == 'node' & !empty($data['node']))) {
$entity = !empty($data['entity']) ? $data['entity'] : $data['node'];
foreach ($tokens as $name => $original) {
switch($name) {
case 'comment-count':
$replacements[$original] = $node->comment_count;
$count = 0;
$fields = array_keys(\Drupal::service('comment.manager')->getFields($entity->entityType()));
$definitions = array_keys($entity->getPropertyDefinitions());
$valid_fields = array_intersect($fields, $definitions);
foreach ($valid_fields as $field_name) {
$count += $entity->get($field_name)->comment_count;
}
$replacements[$original] = $count;
break;
case 'comment-count-new':
$replacements[$original] = comment_num_new($node->id());
$replacements[$original] = comment_num_new($entity->id(), $entity->entityType());
break;
}
}
......
......@@ -98,7 +98,7 @@ function comment_views_data() {
'help' => t('Hostname of user that posted the comment.'),
'field' => array(
'id' => 'standard',
),
),
'filter' => array(
'id' => 'string',
),
......@@ -115,7 +115,7 @@ function comment_views_data() {
'help' => t('E-mail of user that posted the comment. Will be empty if the author is a registered user.'),
'field' => array(
'id' => 'standard',
),
),
'filter' => array(
'id' => 'string',
),
......@@ -300,16 +300,11 @@ function comment_views_data() {
),
);
$data['comment']['nid'] = array(
'title' => t('Nid'),
'help' => t('The node ID to which the comment is a reply to.'),
'relationship' => array(
'title' => t('Content'),
'help' => t('The content to which the comment is a reply to.'),
'base' => 'node',
'base field' => 'nid',
$data['comment']['entity_id'] = array(
'title' => t('Entity ID'),
'help' => t('The Entity ID to which the comment is a reply to.'),
'field' => array(
'id' => 'standard',
'label' => t('Content'),
),
'filter' => array(
'id' => 'numeric',
......@@ -317,11 +312,74 @@ function comment_views_data() {
'argument' => array(
'id' => 'numeric',
),
'sort' => array(
'id' => 'standard',
),
);
$data['comment']['entity_type'] = array(
'title' => t('Entity type'),
'help' => t('The Entity type to which the comment is a reply to.'),
'field' => array(
'id' => 'numeric',
'id' => 'standard',
),
'filter' => array(
'id' => 'string',
),
'argument' => array(
'id' => 'string',
),
'sort' => array(
'id' => 'standard',
),
);
$data['comment']['field_id'] = array(
'title' => t('Comment field id'),
'help' => t('The Field id from which the comment originated.'),
'field' => array(
'id' => 'standard',
),
'filter' => array(
'id' => 'string',
),
'argument' => array(
'id' => 'string',
),
'sort' => array(
'id' => 'standard',
),
);
$entities_info = \Drupal::entityManager()->getDefinitions();
// Provide a relationship for each entity type except comment.
foreach ($entities_info as $type => $entity_info) {
if ($type == 'comment' || empty($entity_info['fieldable']) || !isset($entity_info['base_table'])) {
continue;
}
if ($fields = \Drupal::service('comment.manager')->getFields($type)) {
$data['comment'][$type] = array(
'relationship' => array(
'title' => $entity_info['label'],
'help' => t('The @entity_type to which the comment is a reply to.', array('@entity_type' => $entity_info['label'])),
'base' => $entity_info['base_table'],
'base field' => $entity_info['entity_keys']['id'],
'relationship field' => 'entity_id',
'id' => 'standard',
'label' => $entity_info['label'],
'extra' => array(
array(
'field' => 'entity_type',
'value' => $type,
'table' => 'comment'
),
),
),
);
}
}
$data['comment']['uid'] = array(
'title' => t('Author uid'),
'help' => t('If you need more fields than the uid add the comment: author relationship'),
......@@ -372,18 +430,35 @@ function comment_views_data() {
// Define the base group of this table. Fields that don't have a group defined
// will go into this field by default.
$data['node_comment_statistics']['table']['group'] = t('Content');
// Explain how this table joins to others.
$data['node_comment_statistics']['table']['join'] = array(
'node' => array(
'type' => 'INNER',
'left_field' => 'nid',
'field' => 'nid',
),
);
$data['comment_entity_statistics']['table']['group'] = t('Comment Statistics');
// Provide a relationship for each entity type except comment.
foreach ($entities_info as $type => $entity_info) {
if ($type == 'comment' || empty($entity_info['fieldable']) || !isset($entity_info['base_table'])) {
continue;
}
// This relationship does not use the 'field id' column, if the entity has
// multiple comment-fields, then this might introduce duplicates, in which
// case the site-builder should enable aggregation and SUM the comment_count
// field. We cannot create a relationship from the base table to
// {comment_entity_statistics} for each field as multiple joins between
// the same two tables is not supported.
if (\Drupal::service('comment.manager')->getFields($type)) {
$data['comment_entity_statistics']['table']['join'][$entity_info['base_table']] = array(
'type' => 'INNER',
'left_field' => $entity_info['entity_keys']['id'],
'field' => 'entity_id',
'extra' => array(
array(
'field' => 'entity_type',
'value' => $type,
),
),
);
}
}
$data['node_comment_statistics']['last_comment_timestamp'] = array(
$data['comment_entity_statistics']['last_comment_timestamp'] = array(
'title' => t('Last comment time'),
'help' => t('Date and time of when the last comment was posted.'),
'field' => array(
......@@ -397,22 +472,22 @@ function comment_views_data() {
),
);
$data['node_comment_statistics']['last_comment_name'] = array(
$data['comment_entity_statistics']['last_comment_name'] = array(