Commit 4e3ee43e authored by catch's avatar catch

Issue #2228763 by larowlan, alexpott, martin107, jessebeach, xjm: Create a...

Issue #2228763 by larowlan, alexpott, martin107, jessebeach, xjm: Create a comment-type config entity and use that as comment bundles, require selection in field settings form.
parent 1d47e0a0
......@@ -243,7 +243,7 @@ public function deleteRevision() { }
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, array &$form_state, $has_data) {
public function settingsForm(array &$form, array &$form_state, $has_data) {
return array();
}
......
......@@ -252,7 +252,7 @@ public static function defaultInstanceSettings();
* @return
* The form definition for the field settings.
*/
public function settingsForm(array $form, array &$form_state, $has_data);
public function settingsForm(array &$form, array &$form_state, $has_data);
/**
* Returns a form for the instance-level settings.
......
......@@ -63,7 +63,7 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, array &$form_state, $has_data) {
public function settingsForm(array &$form, array &$form_state, $has_data) {
$element = array();
$settings = $this->getSettings();
......
......@@ -5,6 +5,8 @@
* Install, update and uninstall functions for the Comment module.
*/
use Drupal\field\Entity\FieldConfig;
/**
* Implements hook_uninstall().
*/
......@@ -49,12 +51,12 @@ function comment_schema() {
'length' => 255,
'description' => 'The entity_type of the entity to which this comment is a reply.',
),
'field_id' => array(
'field_name' => array(
'type' => 'varchar',
'not null' => TRUE,
'default' => 'node__comment',
'length' => 255,
'description' => 'The field_id of the field that was used to add this comment.',
'default' => '',
'length' => FieldConfig::NAME_MAX_LENGTH,
'description' => 'The field_name of the field that was used to add this comment.',
),
'cid' => array(
'type' => 'int',
......@@ -89,7 +91,7 @@ function comment_schema() {
'description' => 'The total number of comments on this entity.',
),
),
'primary key' => array('entity_id', array('entity_type', 32), array('field_id', 32)),
'primary key' => array('entity_id', 'entity_type', 'field_name'),
'indexes' => array(
'last_comment_timestamp' => array('last_comment_timestamp'),
'comment_count' => array('comment_count'),
......
comment_type_add:
route_name: comment.type_add
title: 'Add comment type'
appears_on:
- comment.type_list
......@@ -29,3 +29,9 @@ comment.admin_approval:
class: Drupal\comment\Plugin\Menu\LocalTask\UnapprovedComments
parent_id: comment.admin
weight: 1
# Default tab for comment type editing.
comment.type_edit:
title: 'Edit'
route_name: comment.type_edit
base_route: comment.type_edit
......@@ -3,8 +3,8 @@ comment.admin:
route_name: comment.admin
parent: system.admin_content
description: 'List and edit site comments and the comment approval queue.'
comment.bundle_list:
title: 'Comment forms'
route_name: comment.bundle_list
comment.type_list:
title: 'Comment types'
route_name: comment.type_list
parent: system.admin_structure
description: 'Manage fields and displays settings for comment forms.'
description: 'Manage form and displays settings of comments.'
This diff is collapsed.
......@@ -66,20 +66,6 @@ comment.new_comments_node_links:
requirements:
_permission: 'access content'
comment.bundle_list:
path: '/admin/structure/comments'
defaults:
_content: '\Drupal\comment\Controller\AdminController::overviewBundles'
_title: 'Comment forms'
requirements:
_permission: 'administer comments'
# This route is only used by Field UI.
comment.bundle:
path: '/admin/structure/comments/manage/{bundle}'
requirements:
_access: 'FALSE'
comment.node_redirect:
path: '/comment/{node}/reply'
defaults:
......@@ -87,3 +73,43 @@ comment.node_redirect:
requirements:
_entity_access: 'node.view'
_module_dependencies: 'node'
comment.type_list:
path: '/admin/structure/comment'
defaults:
_entity_list: 'comment_type'
_title: 'Comment types'
requirements:
_permission: 'administer comment types'
options:
_admin_route: TRUE
comment.type_delete:
path: '/admin/structure/comment/manage/{comment_type}/delete'
defaults:
_entity_form: 'comment_type.delete'
_title: 'Delete'
requirements:
_entity_access: 'comment_type.delete'
options:
_admin_route: TRUE
comment.type_add:
path: '/admin/structure/comment/types/add'
defaults:
_entity_form: 'comment_type.add'
_title: 'Add'
requirements:
_permission: 'administer comment types'
options:
_admin_route: TRUE
comment.type_edit:
path: '/admin/structure/comment/manage/{comment_type}'
defaults:
_entity_form: 'comment_type.edit'
_title: 'Edit'
requirements:
_entity_access: 'comment_type.update'
options:
_admin_route: TRUE
......@@ -12,9 +12,3 @@ services:
comment.statistics:
class: Drupal\comment\CommentStatistics
arguments: ['@database', '@current_user', '@entity.manager', '@state']
comment.route_enhancer:
class: Drupal\comment\Routing\CommentBundleEnhancer
arguments: ['@entity.manager']
tags:
- { name: route_enhancer}
......@@ -332,9 +332,26 @@ function comment_views_data() {
),
);
$data['comment']['field_id'] = array(
'title' => t('Comment field id'),
'help' => t('The Field id from which the comment originated.'),
$data['comment']['field_name'] = array(
'title' => t('Comment field name'),
'help' => t('The Field name from which the comment originated.'),
'field' => array(
'id' => 'standard',
),
'filter' => array(
'id' => 'string',
),
'argument' => array(
'id' => 'string',
),
'sort' => array(
'id' => 'standard',
),
);
$data['comment']['comment_type'] = array(
'title' => t('Comment type'),
'help' => t('The comment type for this comment.'),
'field' => array(
'id' => 'standard',
),
......@@ -567,9 +584,9 @@ function comment_views_data() {
'id' => 'standard',
),
);
$data['comment_entity_statistics']['field_id'] = array(
'title' => t('Comment field ID'),
'help' => t('The field ID from which the comment originated.'),
$data['comment_entity_statistics']['field_name'] = array(
'title' => t('Comment field name'),
'help' => t('The field name from which the comment originated.'),
'field' => array(
'id' => 'standard',
),
......@@ -666,8 +683,8 @@ function comment_views_data_alter(&$data) {
'value' => $entity_type_id,
),
array(
'field' => 'field_id',
'value' => $entity_type_id . '.' . $field_name,
'field' => 'field_name',
'value' => $field_name,
),
),
),
......
......@@ -43,6 +43,16 @@ action.configuration.comment_unpublish_action:
type: action_configuration_default
label: 'Unpublish comment configuration'
comment.type.*:
type: config_entity
label: 'Comment type settings'
mapping:
target_entity_type_id:
type: string
label: 'Target Entity Type ID'
description:
type: text
label: 'Description'
field.comment.settings:
type: sequence
......
<?php
/**
* @file
* Contains \Drupal\comment\CommentFieldNameItem.
*/
namespace Drupal\comment;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
use Drupal\Core\TypedData\DataDefinition;
/**
* The field item for the 'fieldname' field.
*/
class CommentFieldNameItem extends StringItem {
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['value'] = DataDefinition::create('string')
->setLabel(t('String value'))
->setClass('\Drupal\comment\CommentFieldNameValue')
->setComputed(TRUE);
return $properties;
}
}
<?php
/**
* @file
* Contains \Drupal\comment\CommentFieldNameValue.
*/
namespace Drupal\comment;
use Drupal\Core\TypedData\TypedData;
use Drupal\Core\TypedData\ReadOnlyException;
use InvalidArgumentException;
/**
* A computed property for the string value of the field_name field.
*/
class CommentFieldNameValue extends TypedData {
/**
* {@inheritdoc}
*/
public function getValue() {
if (!isset($this->value)) {
if (!isset($this->parent)) {
throw new InvalidArgumentException('Computed properties require context for computation.');
}
$field = $this->parent->getParent();
$entity = $field->getParent();
// Field id is of the form {entity_type}__{field_name}. We set the
// optional limit param to explode() in case the user adds a field with __
// in the name.
$parts = explode('__', $entity->getFieldId(), 2);
if ($parts && count($parts) == 2) {
$this->value = end($parts);
}
}
return $this->value;
}
/**
* {@inheritdoc}
*/
public function setValue($value, $notify = TRUE) {
if (isset($value)) {
$this->field_name = $value;
// Also set the field id.
$field = $this->parent->getParent();
$entity = $field->getParent();
$entity->field_id = $entity->getCommentedEntityTypeId() . '__' . $value;
}
}
}
......@@ -14,6 +14,7 @@
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -156,6 +157,15 @@ public function form(array $form, array &$form_state) {
$form['author']['name']['#account'] = $this->currentUser;
}
$language_configuration = \Drupal::moduleHandler()->invoke('language', 'get_default_configuration', array('comment', $comment->getTypeId()));
$form['langcode'] = array(
'#title' => t('Language'),
'#type' => 'language_select',
'#default_value' => $comment->getUntranslated()->language()->id,
'#languages' => Language::STATE_ALL,
'#access' => isset($language_configuration['language_show']) && $language_configuration['language_show'],
);
// Add author email and homepage fields depending on the current user.
$form['author']['mail'] = array(
'#type' => 'email',
......@@ -211,13 +221,6 @@ public function form(array $form, array &$form_state) {
'#value' => ($comment->id() ? !$comment->getOwnerId() : $this->currentUser->isAnonymous()),
);
// Add internal comment properties.
$original = $comment->getUntranslated();
foreach (array('cid', 'pid', 'entity_id', 'entity_type', 'field_id', 'uid', 'langcode') as $key) {
$key_name = key($comment->$key->getFieldDefinition()->getPropertyDefinitions());
$form[$key] = array('#type' => 'value', '#value' => $original->$key->{$key_name});
}
return parent::form($form, $form_state, $comment);
}
......@@ -263,8 +266,9 @@ protected function actions(array $form, array &$form_state) {
*/
public function validate(array $form, array &$form_state) {
parent::validate($form, $form_state);
$entity = $this->entity;
if (!empty($form_state['values']['cid'])) {
if (!$entity->isNew()) {
// Verify the name in case it is being changed from being anonymous.
$accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $form_state['values']['name']));
$account = reset($accounts);
......@@ -364,8 +368,8 @@ public function preview(array &$form, array &$form_state) {
* Overrides Drupal\Core\Entity\EntityForm::save().
*/
public function save(array $form, array &$form_state) {
$entity = entity_load($form_state['values']['entity_type'], $form_state['values']['entity_id']);
$comment = $this->entity;
$entity = $comment->getCommentedEntity();
$field_name = $comment->getFieldName();
$uri = $entity->urlInfo();
......
......@@ -66,25 +66,16 @@ public function getCommentedEntityId();
*/
public function getCommentedEntityTypeId();
/**
* Returns the field ID of the comment field the comment is attached to.
*
* @return string
* The field identifier of the field the comment is attached to.
*/
public function getFieldId();
/**
* Sets the field ID for which this comment is attached.
*
* @param string $field_id
* The field identifier, usually formatted: {entity_type}__{field_name},
* for example, node__comment.
* @param string $field_name
* The field name through which the comment was added.
*
* @return $this
* The class instance that this method is called on.
*/
public function setFieldId($field_id);
public function setFieldName($field_name);
/**
* Returns the name of the field the comment is attached to.
......@@ -258,4 +249,12 @@ public function setThread($thread);
*/
public function permalink();
/**
* Get the comment type id for this comment.
*
* @return string
* The id of the comment type.
*/
public function getTypeId();
}
......@@ -9,6 +9,7 @@
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
......@@ -16,6 +17,8 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldInstanceConfig;
/**
* Comment manager contains common functions to manage comment fields.
......@@ -103,9 +106,27 @@ public function getAllFields() {
/**
* {@inheritdoc}
*/
public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN) {
public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN, $comment_type_id = 'comment') {
$comment_type_storage = $this->entityManager->getStorage('comment_type');
if ($comment_type = $comment_type_storage->load($comment_type_id)) {
if ($comment_type->getTargetEntityTypeId() !== $entity_type) {
throw new \InvalidArgumentException(String::format('The given comment type id %id can only be used with the %entity_type entity type', array(
'%id' => $comment_type_id,
'%entity_type' => $entity_type,
)));
}
}
else {
// Silently create the comment-type for the calling code.
$comment_type_storage->create(array(
'id' => $comment_type_id,
'label' => Unicode::ucfirst($comment_type_id),
'target_entity_type_id' => $entity_type,
'description' => 'Default comment field',
))->save();
}
// Make sure the field doesn't already exist.
if (!$this->entityManager->getStorage('field_config')->load($entity_type . '.' . $field_name)) {
if (!FieldConfig::loadByName($entity_type, $field_name)) {
// Add a default comment field for existing node comments.
$field = $this->entityManager->getStorage('field_config')->create(array(
'entity_type' => $entity_type,
......@@ -113,14 +134,14 @@ public function addDefaultField($entity_type, $bundle, $field_name = 'comment',
'type' => 'comment',
'translatable' => '0',
'settings' => array(
'description' => 'Default comment field',
'comment_type' => $comment_type_id,
),
));
// Create the field.
$field->save();
}
// Make sure the instance doesn't already exist.
if (!$this->entityManager->getStorage('field_instance_config')->load($entity_type . '.' . $bundle . '.' . $field_name)) {
if (!array_key_exists($field_name, $this->entityManager->getFieldDefinitions($entity_type, $bundle))) {
$instance = $this->entityManager->getStorage('field_instance_config')->create(array(
'label' => 'Comment settings',
'description' => '',
......@@ -164,7 +185,7 @@ public function addDefaultField($entity_type, $bundle, $field_name = 'comment',
'weight' => 20,
))
->save();
// The comment field should be hidden in all other view displays.
// The comment field should be hidden in all other view displays.
foreach ($this->entityManager->getViewModes($entity_type) as $id => $view_mode) {
$display = entity_get_display($entity_type, $bundle, $id);
// Only update existing displays.
......@@ -174,15 +195,15 @@ public function addDefaultField($entity_type, $bundle, $field_name = 'comment',
}
}
$this->addBodyField($entity_type, $field_name);
$this->addBodyField($comment_type_id);
}
/**
* {@inheritdoc}
*/
public function addBodyField($entity_type, $field_name) {
public function addBodyField($comment_type_id) {
// Create the field if needed.
$field = $this->entityManager->getStorage('field_config')->load('comment.comment_body');
$field = FieldConfig::loadByName('comment', 'comment_body');
if (!$field) {
$field = $this->entityManager->getStorage('field_config')->create(array(
'name' => 'comment_body',
......@@ -191,32 +212,27 @@ public function addBodyField($entity_type, $field_name) {
));
$field->save();
}
// Create the instance if needed, field name defaults to 'comment'.
$comment_bundle = $entity_type . '__' . $field_name;
$field_instance = $this->entityManager
->getStorage('field_instance_config')
->load("comment.$comment_bundle.comment_body");
if (!$field_instance) {
if (!FieldInstanceConfig::loadByName('comment', $comment_type_id, 'comment_body')) {
// Attaches the body field by default.
$field_instance = $this->entityManager->getStorage('field_instance_config')->create(array(
'field_name' => 'comment_body',
'label' => 'Comment',
'entity_type' => 'comment',
'bundle' => $comment_bundle,
'bundle' => $comment_type_id,
'settings' => array('text_processing' => 1),
'required' => TRUE,
));
$field_instance->save();
// Assign widget settings for the 'default' form mode.
entity_get_form_display('comment', $comment_bundle, 'default')
entity_get_form_display('comment', $comment_type_id, 'default')
->setComponent('comment_body', array(
'type' => 'text_textarea',
))
->save();
// Assign display settings for the 'default' view mode.
entity_get_display('comment', $comment_bundle, 'default')
entity_get_display('comment', $comment_type_id, 'default')
->setComponent('comment_body', array(
'label' => 'hidden',
'type' => 'text_default',
......@@ -226,16 +242,6 @@ public function addBodyField($entity_type, $field_name) {
}
}
/**
* {@inheritdoc}
*/
public function getFieldUIPageTitle($commented_entity_type, $field_name) {
$field_info = $this->getFields($commented_entity_type);
$sample_bundle = reset($field_info[$field_name]['bundles']);
$sample_definition = $this->entityManager->getFieldDefinitions($commented_entity_type, $sample_bundle)[$field_name];
return String::checkPlain($sample_definition->getLabel());
}
/**
* {@inheritdoc}
*/
......
......@@ -48,36 +48,24 @@ public function getAllFields();
* @param string $bundle
* The bundle to attach the default comment field instance to.
* @param string $field_name
* (optional) Field name to use for the comment field. Defaults to 'comment'.
* (optional) Field name to use for the comment field. Defaults to
* 'comment'.
* @param int $default_value
* (optional) Default value, one of CommentItemInterface::HIDDEN,
* CommentItemInterface::OPEN, CommentItemInterface::CLOSED. Defaults to
* CommentItemInterface::OPEN.
* @param string $comment_type_id
* (optional) ID of comment type to use. Defaults to 'comment'.
*/
public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN);
public function addDefaultField($entity_type, $bundle, $field_name = 'comment', $default_value = CommentItemInterface::OPEN, $comment_type_id = 'comment');
/**
* Creates a comment_body field instance.
*
* @param string $entity_type
* The type of the entity to which the comment field attached.
* @param string $field_name
* Name of the comment field to add comment_body field.
*/
public function addBodyField($entity_type, $field_name);
/**
* Builds human readable page title for field_ui management screens.
*
* @param string $commented_entity_type
* The entity type to which the comment field is attached.
* @param string $field_name
* The comment field for which the overview is to be displayed.
*
* @return string
* The human readable field name.
* @param string $comment_type
* The comment bundle.
*/
public function getFieldUIPageTitle($commented_entity_type, $field_name);
public function addBodyField($comment_type);
/**
* Provides a message if posting comments is forbidden.
......
......@@ -95,7 +95,7 @@ public function create(ContentEntityInterface $entity, $fields) {
->fields(array(
'entity_id',
'entity_type',
'field_id',
'field_name',
'cid',
'last_comment_timestamp',
'last_comment_name',
......@@ -126,7 +126,7 @@ public function create(ContentEntityInterface $entity, $fields) {
$query->values(array(
'entity_id' => $entity->id(),
'entity_type' => $entity->getEntityTypeId(),
'field_id' => $entity->getEntityTypeId() . '__' . $field_name,
'field_name' => $field_name,
'cid' => 0,
'last_comment_timestamp' => $last_comment_timestamp,
'last_comment_name' => NULL,
......@@ -157,7 +157,7 @@ public function getRankingInfo() {
'alias' => 'ces',
// Default to comment field as this is the most common use case for
// nodes.
'on' => "ces.entity_id = i.sid AND ces.entity_type = 'node' AND ces.field_id = 'node__comment'",
'on' => "ces.entity_id = i.sid AND ces.entity_type = 'node' AND ces.field_name = 'comment'",
),
// Inverse law that maps the highest reply count on the site to 1 and 0
// to 0. Note that the CAST here is necessary for PostgreSQL, because the
......@@ -183,7 +183,7 @@ public function update(CommentInterface $comment) {
$query->addExpression('COUNT(cid)');
$count = $query->condition('c.entity_id', $comment->getCommentedEntityId())
->condition('c.entity_type', $comment->getCommentedEntityTypeId())
->condition('c.field_id', $comment->getFieldId())
->condition('c.field_name', $comment->getFieldName())
->condition('c.status', CommentInterface::PUBLISHED)
->execute()
->fetchField();
......@@ -194,7 +194,7 @@ public function update(CommentInterface $comment) {
->fields('c', array('cid', 'name', 'changed', 'uid'))
->condition('c.entity_id', $comment->getCommentedEntityId())
->condition('c.entity_type', $comment->getCommentedEntityTypeId())
->condition('c.field_id', $comment->getFieldId())
->condition('c.field_name', $comment->getFieldName())
->condition('c.status', CommentInterface::PUBLISHED)
->orderBy('c.created', 'DESC')
->range(0, 1)
......@@ -212,7 +212,7 @@ public function update(CommentInterface $comment) {
->keys(array(
'entity_id' => $comment->getCommentedEntityId(),
'entity_type' => $comment->getCommentedEntityTypeId(),
'field_id' => $comment->getFieldId(),
'field_name' => $comment->getFieldName(),
))
->execute();
}
......@@ -241,7 +241,7 @@ public function update(CommentInterface $comment) {
))
->condition('entity_id', $comment->getCommentedEntityId())
->condition('entity_type', $comment->getCommentedEntityTypeId())
->condition('field_id', $comment->getFieldId())
->condition('field_name', $comment->getFieldName())
->execute();
}
}
......
......@@ -95,7 +95,7 @@ public function updateEntityStatistics(CommentInterface $comment) {
public function getMaxThread(EntityInterface $comment) {
$query = $this->database->select('comment', 'c')
->condition('entity_id', $comment->getCommentedEntityId())
->condition('field_id', $comment->getFieldId())
->condition('field_name', $comment->getFieldName())
->condition('entity_type', $comment->getCommentedEntityTypeId());
$query->addExpression('MAX(thread)', 'thread');