Commit 9d61b04b authored by catch's avatar catch

Issue #2322949 by plach, kgoel, Berdir, fgm, damiankloip, dawehner: Implement...

Issue #2322949 by plach, kgoel, Berdir, fgm, damiankloip, dawehner: Implement generic entity link view field handlers
parent e0aae8c2
......@@ -28,18 +28,6 @@ public function getViewsData() {
$data['block_content_field_data']['type']['field']['id'] = 'field';
// @todo Figure out the way to integrate this automatic in
// content_translation https://www.drupal.org/node/2410261.
if ($this->moduleHandler->moduleExists('content_translation')) {
$data['block_content']['translation_link'] = array(
'title' => $this->t('Translation link'),
'help' => $this->t('Provide a link to the translations overview for custom blocks.'),
'field' => array(
'id' => 'content_translation_link',
),
);
}
// Advertise this table as a possible base table.
$data['block_content_revision']['table']['base']['help'] = $this->t('Block Content revision is a history of changes to block content.');
$data['block_content_revision']['table']['base']['defaults']['title'] = 'info';
......
......@@ -20,33 +20,10 @@ views.field.comment_last_timestamp:
type: views.field.date
label: 'Last comment date'
views.field.comment_link:
type: views_field
label: 'Comment link'
mapping:
text:
type: views_field
label: 'Text to display'
link_to_entity:
type: views_field
label: 'Link field to the entity if there is no comment'
views.field.comment_link_approve:
type: views.field.comment_link
label: 'Comment approve link'
views.field.comment_link_delete:
type: views.field.comment_link
label: 'Comment delete link'
views.field.comment_link_edit:
type: views.field.comment_link
label: 'Comment edit link'
mapping:
destination:
type: boolean
label: 'Use destination'
views.field.comment_link_reply:
type: views.field.comment_link
label: 'Comment reply link'
......
......@@ -25,9 +25,16 @@ class CommentAccessControlHandler extends EntityAccessControlHandler {
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
/** @var \Drupal\Core\Entity\EntityInterface|\Drupal\user\EntityOwnerInterface $entity */
/** @var \Drupal\comment\CommentInterface|\Drupal\user\EntityOwnerInterface $entity */
if ($account->hasPermission('administer comments')) {
$comment_admin = $account->hasPermission('administer comments');
if ($operation == 'approve') {
return AccessResult::allowedIf($comment_admin && !$entity->isPublished())
->cachePerPermissions()
->cacheUntilEntityChanges($entity);
}
if ($comment_admin) {
$access = AccessResult::allowed()->cachePerPermissions();
return ($operation != 'view') ? $access : $access->andIf($entity->getCommentedEntity()->access($operation, $account, TRUE));
}
......
......@@ -102,30 +102,6 @@ public function getViewsData() {
$data['comment_field_data']['status']['filter']['label'] = t('Approved comment status');
$data['comment_field_data']['status']['filter']['type'] = 'yes-no';
$data['comment']['view_comment'] = array(
'field' => array(
'title' => t('Link to comment'),
'help' => t('Provide a simple link to view the comment.'),
'id' => 'comment_link',
),
);
$data['comment']['edit_comment'] = array(
'field' => array(
'title' => t('Link to edit comment'),
'help' => t('Provide a simple link to edit the comment.'),
'id' => 'comment_link_edit',
),
);
$data['comment']['delete_comment'] = array(
'field' => array(
'title' => t('Link to delete comment'),
'help' => t('Provide a simple link to delete the comment.'),
'id' => 'comment_link_delete',
),
);
$data['comment']['approve_comment'] = array(
'field' => array(
'title' => t('Link to approve comment'),
......@@ -195,16 +171,6 @@ public function getViewsData() {
$data['comment_field_data']['pid']['relationship']['help'] = t('The parent comment');
$data['comment_field_data']['pid']['relationship']['label'] = t('parent');
if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
$data['comment']['translation_link'] = array(
'title' => t('Translation link'),
'help' => t('Provide a link to the translations overview for comments.'),
'field' => array(
'id' => 'content_translation_link',
),
);
}
// Define the base group of this table. Fields that don't have a group defined
// will go into this field by default.
$data['comment_entity_statistics']['table']['group'] = t('Comment Statistics');
......
......@@ -7,9 +7,8 @@
namespace Drupal\comment\Plugin\views\field;
use Drupal\comment\CommentInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\views\Plugin\views\field\LinkBase;
use Drupal\views\ResultRow;
/**
......@@ -19,43 +18,28 @@
*
* @ViewsField("comment_link_approve")
*/
class LinkApprove extends Link {
class LinkApprove extends LinkBase {
/**
* {@inheritdoc}
*/
public function access(AccountInterface $account) {
//needs permission to administer comments in general
return $account->hasPermission('administer comments');
protected function getUrlInfo(ResultRow $row) {
return Url::fromRoute('comment.approve', ['comment' => $this->getEntity($row)->id()]);
}
/**
* Prepares the link pointing for approving the comment.
*
* @param \Drupal\Core\Entity\EntityInterface $data
* The comment entity.
* @param \Drupal\views\ResultRow $values
* The values retrieved from a single row of a view's query result.
*
* @return string
* Returns a string for the link text.
* {@inheritdoc}
*/
protected function renderLink($data, ResultRow $values) {
$status = $this->getValue($values, 'status');
// Don't show an approve link on published comment.
if ($status == CommentInterface::PUBLISHED) {
return;
}
$text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Approve');
$comment = $this->get_entity($values);
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['url'] = Url::fromRoute('comment.approve', ['comment' => $comment->id()]);
$this->options['alter']['query'] = $this->getDestinationArray() + array('token' => \Drupal::csrfToken()->get($this->options['alter']['url']->toString()));
protected function renderLink(ResultRow $row) {
$this->options['alter']['query'] = $this->getDestinationArray();
return parent::renderLink($row);
}
return $text;
/**
* {@inheritdoc}
*/
protected function getDefaultLabel() {
return $this->t('Approve');
}
}
<?php
/**
* @file
* Contains \Drupal\comment\Plugin\views\field\LinkDelete.
*/
namespace Drupal\comment\Plugin\views\field;
use Drupal\Core\Session\AccountInterface;
use Drupal\views\ResultRow;
/**
* Field handler to present a link to delete a comment.
*
* @ingroup views_field_handlers
*
* @ViewsField("comment_link_delete")
*/
class LinkDelete extends Link {
/**
* {@inheritdoc}
*/
public function access(AccountInterface $account) {
//needs permission to administer comments in general
return $account->hasPermission('administer comments');
}
/**
* Prepares the link for deleting the comment.
*
* @param \Drupal\Core\Entity\EntityInterface $data
* The comment entity.
* @param \Drupal\views\ResultRow $values
* The values retrieved from a single row of a view's query result.
*
* @return string
* Returns a string for the link text.
*/
protected function renderLink($data, ResultRow $values) {
$text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Delete');
$comment = $this->getEntity($values);
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['url'] = $comment->urlInfo('delete-form');
$this->options['alter']['query'] = $this->getDestinationArray();
return $text;
}
}
<?php
/**
* @file
* Contains \Drupal\comment\Plugin\views\field\LinkEdit.
*/
namespace Drupal\comment\Plugin\views\field;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\ResultRow;
/**
* Field handler to present a link to edit a comment.
*
* @ingroup views_field_handlers
*
* @ViewsField("comment_link_edit")
*/
class LinkEdit extends Link {
protected function defineOptions() {
$options = parent::defineOptions();
$options['destination'] = array('default' => FALSE);
return $options;
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['destination'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Use destination'),
'#description' => $this->t('Add destination to the link'),
'#default_value' => $this->options['destination'],
);
}
/**
* Prepare the link for editing the comment.
*
* @param \Drupal\Core\Entity\EntityInterface $data
* The comment entity.
* @param \Drupal\views\ResultRow $values
* The values retrieved from a single row of a view's query result.
*
* @return string
* Returns a string for the link text.
*/
protected function renderLink($data, ResultRow $values) {
parent::renderLink($data, $values);
// Ensure user has access to edit this comment.
$comment = $this->getValue($values);
if (!$comment->access('update')) {
return;
}
$text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit');
unset($this->options['alter']['fragment']);
if (!empty($this->options['destination'])) {
$this->options['alter']['query'] = $this->getDestinationArray();
}
$this->options['alter']['url'] = $comment->urlInfo('edit-form');
return $text;
}
}
......@@ -7,8 +7,8 @@
namespace Drupal\comment\Plugin\views\field;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\views\Plugin\views\field\LinkBase;
use Drupal\views\ResultRow;
/**
......@@ -18,39 +18,27 @@
*
* @ViewsField("comment_link_reply")
*/
class LinkReply extends Link {
class LinkReply extends LinkBase {
/**
* {@inheritdoc}
*/
public function access(AccountInterface $account) {
//check for permission to reply to comments
return $account->hasPermission('post comments');
}
/**
* Prepare the link for replying to the comment.
*
* @param \Drupal\Core\Entity\EntityInterface $data
* The comment entity.
* @param \Drupal\views\ResultRow $values
* The values retrieved from a single row of a view's query result.
*
* @return string
* Returns a string for the link text.
*/
protected function renderLink($data, ResultRow $values) {
$text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Reply');
$comment = $this->getEntity($values);
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['url'] = Url::fromRoute('comment.reply', [
protected function getUrlInfo(ResultRow $row) {
/** @var \Drupal\comment\CommentInterface $comment */
$comment = $this->getEntity($row);
return Url::fromRoute('comment.reply', [
'entity_type' => $comment->getCommentedEntityTypeId(),
'entity' => $comment->getCommentedEntityId(),
'field_name' => $comment->getFieldName(),
'pid' => $comment->id(),
]);
return $text;
}
/**
* {@inheritdoc}
*/
protected function getDefaultLabel() {
return $this->t('Reply');
}
}
......@@ -7,14 +7,11 @@
namespace Drupal\contact\Plugin\views\field;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\user\Plugin\views\field\Link;
use Drupal\views\Plugin\views\field\LinkBase;
use Drupal\views\ResultRow;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a field that links to the user contact page, if access is permitted.
......@@ -23,65 +20,7 @@
*
* @ViewsField("contact_link")
*/
class ContactLink extends Link {
/**
* The access manager.
*
* @var \Drupal\Core\Access\AccessManagerInterface
*/
protected $accessManager;
/**
* Current user object.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* Gets the current active user.
*
* @todo: https://drupal.org/node/2105123 put this method in
* \Drupal\Core\Plugin\PluginBase instead.
*
* @return \Drupal\Core\Session\AccountInterface
*/
protected function currentUser() {
if (!$this->currentUser) {
$this->currentUser = \Drupal::currentUser();
}
return $this->currentUser;
}
/**
* Constructs a ContactLink object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Access\AccessManagerInterface $access_manager
* The access manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, AccessManagerInterface $access_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->accessManager = $access_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('access_manager')
);
}
class ContactLink extends LinkBase {
/**
* {@inheritdoc}
......@@ -90,37 +29,26 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['text']['#title'] = $this->t('Link label');
$form['text']['#required'] = TRUE;
$form['text']['#default_value'] = empty($this->options['text']) ? $this->t('contact') : $this->options['text'];
$form['text']['#default_value'] = empty($this->options['text']) ? $this->getDefaultLabel() : $this->options['text'];
}
/**
* {@inheritdoc}
*/
public function access(AccountInterface $account) {
// The access logic is implemented per row.
return TRUE;
protected function getUrlInfo(ResultRow $row) {
return Url::fromRoute('entity.user.contact_form', ['user' => $this->getEntity($row)->id()]);
}
/**
* {@inheritdoc}
*/
protected function renderLink(EntityInterface $entity, ResultRow $values) {
if (empty($entity)) {
return;
}
// Check access when we pull up the user account so we know
// if the user has made the contact page available.
if (!$this->accessManager->checkNamedRoute('entity.user.contact_form', array('user' => $entity->id()), $this->currentUser())) {
return;
}
protected function renderLink(ResultRow $row) {
$entity = $this->getEntity($row);
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['url'] = Url::fromRoute('entity.user.contact_form', ['user' => $entity->id()]);
$this->options['alter']['url'] = $this->getUrlInfo($row);
$title = $this->t('Contact %user', array('%user' => $entity->name->value));
$title = $this->t('Contact %user', array('%user' => $entity->label()));
$this->options['alter']['attributes'] = array('title' => $title);
if (!empty($this->options['text'])) {
......@@ -131,4 +59,11 @@ protected function renderLink(EntityInterface $entity, ResultRow $values) {
}
}
/**
* {@inheritdoc}
*/
protected function getDefaultLabel() {
return $this->t('contact');
}
}
......@@ -220,6 +220,30 @@ function content_translation_entity_operation(EntityInterface $entity) {
return $operations;
}
/**
* Implements hook_views_data_alter().
*/
function content_translation_views_data_alter(array &$data) {
// Add the content translation entity link definition to Views data for entity
// types having translation enabled.
$entity_types = \Drupal::entityManager()->getDefinitions();
/** @var \Drupal\content_translation\ContentTranslationManagerInterface $manager */
$manager = \Drupal::service('content_translation.manager');
foreach ($entity_types as $entity_type_id => $entity_type) {
$base_table = $entity_type->getBaseTable();
if (isset($data[$base_table]) && $entity_type->hasLinkTemplate('drupal:content-translation-overview') && $manager->isEnabled($entity_type_id)) {
$t_arguments = ['@entity_type_label' => $entity_type->getLabel()];
$data[$base_table]['translation_link'] = [
'field' => [
'title' => t('Link to translate @entity_type_label', $t_arguments),
'help' => t('Provide a translation link to the @entity_type_label.', $t_arguments),
'id' => 'content_translation_link',
],
];
}
}
}
/**
* Implements hook_menu_links_discovered_alter().
*/
......
......@@ -7,10 +7,7 @@
namespace Drupal\content_translation\Plugin\views\field;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\views\ResultRow;
use Drupal\views\Plugin\views\field\EntityLink;
/**
* Provides a translation link for an entity.
......@@ -19,69 +16,20 @@
*
* @ViewsField("content_translation_link")
*/
class TranslationLink extends FieldPluginBase {
class TranslationLink extends EntityLink {
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['text'] = array('default' => '');
return $options;
protected function getEntityLinkTemplate() {
return 'drupal:content-translation-overview';
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
$form['text'] = array(
'#type' => 'textfield',
'#title' => $this->t('Text to display'),
'#default_value' => $this->options['text'],
);
parent::buildOptionsForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function render(ResultRow $values) {
return $this->renderLink($this->getEntity($values), $values);
}
/**
* Alters the field to render a link.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being rendered.
* @param \Drupal\views\ResultRow $values
* The current row of the views result.
*
* @return string
* The actual rendered text (without the link) of this field.
*/
protected function renderLink(EntityInterface $entity, ResultRow $values) {
if (content_translation_translate_access($entity)->isAllowed()) {
$text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Translate');
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['url'] = $entity->urlInfo('drupal:content-translation-overview');
return $text;
}
}
/**
* {@inheritdoc}
*/
public function query() {
}
/**
* {@inheritdoc}
*/
public function clickSortable() {
return FALSE;
protected function getDefaultLabel() {
return $this->t('Translate');
}
}
......@@ -239,7 +239,7 @@ display:
hide_alter_empty: true
text: Edit
entity_type: node
plugin_id: node_link_edit
plugin_id: entity_link_edit
delete_node:
id: delete_node
table: node
......@@ -290,7 +290,7 @@ display:
hide_alter_empty: true
text: Delete
entity_type: node
plugin_id: node_link_delete
plugin_id: entity_link_delete
filters:
status_extra:
id: status_extra
......
......@@ -101,30 +101,6 @@ views.field.node:
type: boolean
label: 'Link this field to the original piece of content'
views.field.node_link:
type: views_field
label: 'Node link'
mapping:
text:
type: label
label: 'Text to display'
views.field.node_link_delete:
type: views_field
label: 'Node delete link'
mapping:
text:
type: label
label: 'Text to display'
views.field.node_link_edit:
type: views_field
label: 'Node edit link'
mapping:
text:
type: label
label: 'Text to display'
views.field.node_bulk_form:
type: views_field_bulk_form
label: 'Node bulk form'
......
......@@ -61,40 +61,6 @@ public function getViewsData() {
$data['node_field_data']['sticky']['filter']['type'] = 'yes-no';
$data['node_field_data']['sticky']['sort']['help'] = t('Whether or not the content is sticky. To list sticky content first, set this to descending.');
if (\Drupal::moduleHandler()->moduleExists('content_translation')) {
$data['node']['translation_link'] = array(
'title' => t('Translation link'),
'help' => t('Provide a link to the translations overview for nodes.'),