diff --git a/core/modules/aggregator/config/schema/aggregator.views.schema.yml b/core/modules/aggregator/config/schema/aggregator.views.schema.yml index 23cc642..ff423c5 100644 --- a/core/modules/aggregator/config/schema/aggregator.views.schema.yml +++ b/core/modules/aggregator/config/schema/aggregator.views.schema.yml @@ -9,7 +9,7 @@ views.argument.aggregator_iid: label: 'Aggregator item ID' views.field.aggregator_title_link: - type: views_field + type: views.field.entity_link label: 'Title link' mapping: display_as_link: diff --git a/core/modules/aggregator/src/Plugin/views/field/TitleLink.php b/core/modules/aggregator/src/Plugin/views/field/TitleLink.php index 4fb924f..5b79b92 100644 --- a/core/modules/aggregator/src/Plugin/views/field/TitleLink.php +++ b/core/modules/aggregator/src/Plugin/views/field/TitleLink.php @@ -9,7 +9,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\display\DisplayPluginBase; -use Drupal\views\Plugin\views\field\FieldPluginBase; +use Drupal\views\Plugin\views\field\EntityLink; use Drupal\views\ResultRow; use Drupal\views\ViewExecutable; @@ -21,7 +21,7 @@ * * @ViewsField("aggregator_title_link") */ -class TitleLink extends FieldPluginBase { +class TitleLink extends EntityLink { /** * {@inheritdoc} @@ -75,12 +75,8 @@ public function render(ResultRow $values) { * Returns a string for the link text. */ protected function renderLink($data, ResultRow $values) { - $link = $this->getValue($values, 'link'); if (!empty($this->options['display_as_link'])) { - $this->options['alter']['make_link'] = TRUE; - $this->options['alter']['path'] = $link; - $this->options['alter']['html'] = TRUE; - $this->options['alter']['absolute'] = TRUE; + parent::renderLink($this->getEntity($values), $values); } return $data; diff --git a/core/modules/comment/config/schema/comment.views.schema.yml b/core/modules/comment/config/schema/comment.views.schema.yml index 51953ad..8f345b0 100644 --- a/core/modules/comment/config/schema/comment.views.schema.yml +++ b/core/modules/comment/config/schema/comment.views.schema.yml @@ -46,18 +46,6 @@ 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' diff --git a/core/modules/comment/src/CommentViewsData.php b/core/modules/comment/src/CommentViewsData.php index 2a7083c..069a812 100644 --- a/core/modules/comment/src/CommentViewsData.php +++ b/core/modules/comment/src/CommentViewsData.php @@ -108,30 +108,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'), diff --git a/core/modules/comment/src/Plugin/views/field/LinkDelete.php b/core/modules/comment/src/Plugin/views/field/LinkDelete.php deleted file mode 100644 index f22563b..0000000 --- a/core/modules/comment/src/Plugin/views/field/LinkDelete.php +++ /dev/null @@ -1,52 +0,0 @@ -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']['path'] = $comment->getSystemPath('delete-form'); - $this->options['alter']['query'] = drupal_get_destination(); - - return $text; - } - -} diff --git a/core/modules/comment/src/Plugin/views/field/LinkEdit.php b/core/modules/comment/src/Plugin/views/field/LinkEdit.php deleted file mode 100644 index 4e687a3..0000000 --- a/core/modules/comment/src/Plugin/views/field/LinkEdit.php +++ /dev/null @@ -1,71 +0,0 @@ - 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'] = drupal_get_destination(); - } - - $this->options['alter']['path'] = "comment/" . $comment->id() . "/edit"; - - return $text; - } - -} diff --git a/core/modules/node/config/install/views.view.content.yml b/core/modules/node/config/install/views.view.content.yml index 2a44101..0b08eef 100644 --- a/core/modules/node/config/install/views.view.content.yml +++ b/core/modules/node/config/install/views.view.content.yml @@ -256,7 +256,7 @@ display: label: '' exclude: true text: Edit - plugin_id: node_link_edit + plugin_id: entity_link_edit entity_type: node delete_node: id: delete_node @@ -265,7 +265,7 @@ display: label: '' exclude: true text: Delete - plugin_id: node_link_delete + plugin_id: entity_link_delete entity_type: node dropbutton: id: dropbutton diff --git a/core/modules/node/config/install/views.view.content_recent.yml b/core/modules/node/config/install/views.view.content_recent.yml index 9456436..a20d75c 100644 --- a/core/modules/node/config/install/views.view.content_recent.yml +++ b/core/modules/node/config/install/views.view.content_recent.yml @@ -263,7 +263,7 @@ display: empty_zero: false hide_alter_empty: true text: edit - plugin_id: node_link_edit + plugin_id: entity_link_edit entity_type: node delete_node: id: delete_node @@ -314,7 +314,7 @@ display: empty_zero: false hide_alter_empty: true text: delete - plugin_id: node_link_delete + plugin_id: entity_link_delete entity_type: node filters: status_extra: diff --git a/core/modules/node/config/schema/node.views.schema.yml b/core/modules/node/config/schema/node.views.schema.yml index b1d24d9..9f2a53d 100644 --- a/core/modules/node/config/schema/node.views.schema.yml +++ b/core/modules/node/config/schema/node.views.schema.yml @@ -102,37 +102,13 @@ views.field.node_language: label: 'Native language' views.field.node: - type: views_field + type: views.field.entity_link label: 'Node' mapping: link_to_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' diff --git a/core/modules/node/src/NodeViewsData.php b/core/modules/node/src/NodeViewsData.php index ca2bb26..1e1644f 100644 --- a/core/modules/node/src/NodeViewsData.php +++ b/core/modules/node/src/NodeViewsData.php @@ -36,7 +36,6 @@ public function getViewsData() { $data['node_field_data']['title']['field']['id'] = 'node'; $data['node_field_data']['title']['field']['link_to_node default'] = TRUE; - $data['node_field_data']['type']['field']['id'] = 'node_type'; $data['node_field_data']['type']['argument']['id'] = 'node_type'; $data['node_field_data']['langcode']['help'] = t('The language of the content or translation.'); @@ -83,30 +82,6 @@ public function getViewsData() { ); } - $data['node']['view_node'] = array( - 'field' => array( - 'title' => t('Link to content'), - 'help' => t('Provide a simple link to the content.'), - 'id' => 'node_link', - ), - ); - - $data['node']['edit_node'] = array( - 'field' => array( - 'title' => t('Link to edit content'), - 'help' => t('Provide a simple link to edit the content.'), - 'id' => 'node_link_edit', - ), - ); - - $data['node']['delete_node'] = array( - 'field' => array( - 'title' => t('Link to delete content'), - 'help' => t('Provide a simple link to delete the content.'), - 'id' => 'node_link_delete', - ), - ); - $data['node']['path'] = array( 'field' => array( 'title' => t('Path'), diff --git a/core/modules/node/src/Plugin/views/field/Node.php b/core/modules/node/src/Plugin/views/field/Node.php index a62e0f2..3740639 100644 --- a/core/modules/node/src/Plugin/views/field/Node.php +++ b/core/modules/node/src/Plugin/views/field/Node.php @@ -8,10 +8,10 @@ namespace Drupal\node\Plugin\views\field; use Drupal\Core\Form\FormStateInterface; +use Drupal\views\Plugin\views\field\EntityLink; use Drupal\views\ResultRow; use Drupal\views\ViewExecutable; use Drupal\views\Plugin\views\display\DisplayPluginBase; -use Drupal\views\Plugin\views\field\FieldPluginBase; /** * Field handler to provide simple renderer that allows linking to a node. @@ -22,10 +22,10 @@ * * @ViewsField("node") */ -class Node extends FieldPluginBase { +class Node extends EntityLink { /** - * Overrides \Drupal\views\Plugin\views\field\FieldPluginBase::init(). + * {@inheritdoc} */ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { parent::init($view, $display, $options); @@ -36,6 +36,18 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o } } + /** + * {@inheritdoc} + */ + public function query() { + $this->ensureMyTable(); + // Add the field. + $params = $this->options['group_type'] != 'group' ? array('function' => $this->options['group_type']) : array(); + $this->field_alias = $this->query->addField($this->tableAlias, $this->realField, NULL, $params); + + $this->addAdditionalFields(); + } + protected function defineOptions() { $options = parent::defineOptions(); $options['link_to_node'] = array('default' => isset($this->definition['link_to_node default']) ? $this->definition['link_to_node default'] : FALSE); @@ -72,16 +84,6 @@ protected function renderLink($data, ResultRow $values) { if ($data !== NULL && $data !== '') { $this->options['alter']['make_link'] = TRUE; $this->options['alter']['path'] = "node/" . $this->getValue($values, 'nid'); - if (isset($this->aliases['langcode'])) { - $languages = \Drupal::languageManager()->getLanguages(); - $langcode = $this->getValue($values, 'langcode'); - if (isset($languages[$langcode])) { - $this->options['alter']['language'] = $languages[$langcode]; - } - else { - unset($this->options['alter']['language']); - } - } } else { $this->options['alter']['make_link'] = FALSE; diff --git a/core/modules/user/config/install/views.view.user_admin_people.yml b/core/modules/user/config/install/views.view.user_admin_people.yml index ff62509..8dd2bde 100644 --- a/core/modules/user/config/install/views.view.user_admin_people.yml +++ b/core/modules/user/config/install/views.view.user_admin_people.yml @@ -458,10 +458,10 @@ display: plugin_id: date entity_type: user entity_field: access - edit_node: - id: edit_node + edit_user: + id: edit_user table: users - field: edit_node + field: edit_user relationship: none group_type: group admin_label: '' @@ -507,7 +507,7 @@ display: empty_zero: false hide_alter_empty: true text: Edit - plugin_id: user_link_edit + plugin_id: entity_link_edit entity_type: user dropbutton: id: dropbutton diff --git a/core/modules/user/config/schema/user.views.schema.yml b/core/modules/user/config/schema/user.views.schema.yml index e1b83f3..52aafc7 100644 --- a/core/modules/user/config/schema/user.views.schema.yml +++ b/core/modules/user/config/schema/user.views.schema.yml @@ -83,10 +83,6 @@ views.field.user_link_cancel: type: views.field.user_link label: 'User cancel link' -views.field.user_link_edit: - type: views.field.user_link - label: 'User edit link' - views.field.user_mail: type: views_field_user label: 'User language' diff --git a/core/modules/user/src/Plugin/views/field/LinkEdit.php b/core/modules/user/src/Plugin/views/field/LinkEdit.php deleted file mode 100644 index bb288631..0000000 --- a/core/modules/user/src/Plugin/views/field/LinkEdit.php +++ /dev/null @@ -1,37 +0,0 @@ -access('update')) { - $this->options['alter']['make_link'] = TRUE; - - $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('Edit'); - - $this->options['alter']['url'] = $entity->urlInfo('edit-form', ['query' => ['destination' => drupal_get_destination()]]); - - return $text; - } - } - -} diff --git a/core/modules/user/src/UserViewsData.php b/core/modules/user/src/UserViewsData.php index acf2100..2361f52 100644 --- a/core/modules/user/src/UserViewsData.php +++ b/core/modules/user/src/UserViewsData.php @@ -250,15 +250,6 @@ public function getViewsData() { ); } - $data['users']['edit_node'] = array( - 'field' => array( - 'title' => t('Link to edit user'), - 'help' => t('Provide a simple link to edit the user.'), - 'id' => 'user_link_edit', - 'click sortable' => FALSE, - ), - ); - $data['users']['cancel_node'] = array( 'field' => array( 'title' => t('Link to cancel user'), diff --git a/core/modules/views/config/schema/views.field.schema.yml b/core/modules/views/config/schema/views.field.schema.yml index c515361..574047a 100644 --- a/core/modules/views/config/schema/views.field.schema.yml +++ b/core/modules/views/config/schema/views.field.schema.yml @@ -178,3 +178,27 @@ views.field.xss: views.field.language: type: views_field label: 'Language' + +views.field.entity_link: + type: views_field + label: 'Entity link' + mapping: + text: + type: label + label: 'Text to display' + +views.field.entity_link_delete: + type: views.field.entity_link + label: 'Entity delete link' + mapping: + text: + type: label + label: 'Text to display' + +views.field.entity_link_edit: + type: views.field.entity_link + label: 'Entity edit link' + mapping: + text: + type: label + label: 'Text to display' diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index cb30422..e7188fa 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -183,6 +183,8 @@ public function getViewsData() { } } + $this->addEntityLinks($data[$base_table]); + // Load all typed data definitions of all fields. This should cover each of // the entity base, revision, data tables. $field_definitions = $this->entityManager->getBaseFieldDefinitions($this->entityType->id()); @@ -210,6 +212,44 @@ public function getViewsData() { } /** + * Sets the entity links in case corresponding link templates exist. + * + * @param array $data + * The views data of the base table. + */ + protected function addEntityLinks(array &$data) { + $entity_type_id = $this->entityType->id(); + $t_arguments = ['@entity_type_label' => $this->entityType->getLabel()]; + if ($this->entityType->hasLinkTemplate('canonical')) { + $data['view_' . $entity_type_id] = [ + 'field' => [ + 'title' => $this->t('Link to @entity_type_label', $t_arguments), + 'help' => $this->t('Provide a view link to the @entity_type_label.', $t_arguments), + 'id' => 'entity_link', + ], + ]; + } + if ($this->entityType->hasLinkTemplate('edit-form')) { + $data['edit_' . $entity_type_id] = [ + 'field' => [ + 'title' => $this->t('Link to edit @entity_type_label', $t_arguments), + 'help' => $this->t('Provide an edit link to the @entity_type_label.', $t_arguments), + 'id' => 'entity_link_edit', + ], + ]; + } + if ($this->entityType->hasLinkTemplate('delete-form')) { + $data['delete_' . $entity_type_id] = [ + 'field' => [ + 'title' => $this->t('Link to delete @entity_type_label', $t_arguments), + 'help' => $this->t('Provide a delete link to the @entity_type_label.', $t_arguments), + 'id' => 'entity_link_delete', + ], + ]; + } + } + + /** * Puts the views data for a single field onto the views data. * * @param string $table diff --git a/core/modules/views/src/Plugin/views/field/EntityLink.php b/core/modules/views/src/Plugin/views/field/EntityLink.php new file mode 100644 index 0000000..7cf6fff --- /dev/null +++ b/core/modules/views/src/Plugin/views/field/EntityLink.php @@ -0,0 +1,121 @@ +additional_fields['langcode'] = ['table' => 'node_field_data', 'field' => 'langcode']; + } + + /** + * {@inheritdoc} + */ + public function usesGroupBy() { + return FALSE; + } + + /** + * {@inheritdoc} + */ + protected function defineOptions() { + $options = parent::defineOptions(); + $options['text'] = ['default' => '', 'translatable' => TRUE]; + return $options; + } + + /** + * {@inheritdoc} + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + $form['text'] = [ + '#type' => 'textfield', + '#title' => $this->t('Text to display'), + '#default_value' => $this->options['text'], + ]; + parent::buildOptionsForm($form, $form_state); + + // The path is set by renderLink function so don't allow to set it. + $form['alter']['path'] = ['#access' => FALSE]; + $form['alter']['external'] = ['#access' => FALSE]; + } + + /** + * {@inheritdoc} + */ + public function query() { + $this->addAdditionalFields(); + } + + /** + * {@inheritdoc} + */ + public function render(ResultRow $values) { + if ($entity = $this->getEntity($values)) { + return $this->renderLink($entity, $values); + } + } + + /** + * Prepares the link to view a entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The node entity this field belongs to. + * @param \Drupal\views\ResultRow $values + * The values retrieved from the view's result set. + * + * @return string + * Returns a string for the link text. + */ + protected function renderLink($entity, ResultRow $values) { + if ($entity->access('view')) { + $this->options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = $entity->getSystemPath(); + + $this->addLangcode($values); + + $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('view'); + return $text; + } + } + + /** + * @param \Drupal\views\ResultRow $values + */ + protected function addLangcode(ResultRow $values) { + if (isset($this->aliases['langcode'])) { + $languages = language_list(); + $langcode = $this->getValue($values, 'langcode'); + if (isset($languages[$langcode])) { + $this->options['alter']['language'] = $languages[$langcode]; + } + else { + unset($this->options['alter']['language']); + } + } + } +} diff --git a/core/modules/views/src/Plugin/views/field/EntityLinkDelete.php b/core/modules/views/src/Plugin/views/field/EntityLinkDelete.php new file mode 100644 index 0000000..e08b7bc --- /dev/null +++ b/core/modules/views/src/Plugin/views/field/EntityLinkDelete.php @@ -0,0 +1,46 @@ +access('delete')) { + $this->options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = $entity->getSystemPath('delete-form'); + $this->options['alter']['query'] = drupal_get_destination(); + + $this->addLangcode($values); + + $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('delete'); + return $text; + } + } + +} diff --git a/core/modules/views/src/Plugin/views/field/EntityLinkEdit.php b/core/modules/views/src/Plugin/views/field/EntityLinkEdit.php new file mode 100644 index 0000000..38911b4 --- /dev/null +++ b/core/modules/views/src/Plugin/views/field/EntityLinkEdit.php @@ -0,0 +1,46 @@ +access('update')) { + $this->options['alter']['make_link'] = TRUE; + $this->options['alter']['path'] = $entity->getSystemPath('edit-form'); + $this->options['alter']['query'] = drupal_get_destination(); + + $this->addLangcode($values); + + $text = !empty($this->options['text']) ? $this->options['text'] : $this->t('edit'); + return $text; + } + } + +} diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php index c1aac0f..72bdb42 100644 --- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php +++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php @@ -627,6 +627,33 @@ protected function assertField($data, $field_name) { } /** + * Tests add link types. + */ + public function testEntityLinks() { + $this->baseEntityType->setLinkTemplate('canonical', '/entity_test/{entity_test}'); + $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit'); + $this->baseEntityType->setLinkTemplate('delete-form', '/entity_test/{entity_test}/delete'); + + $data = $this->viewsData->getViewsData(); + $this->assertEquals('entity_link', $data['entity_test']['view_entity_test']['field']['id']); + $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']); + $this->assertEquals('entity_link_delete', $data['entity_test']['delete_entity_test']['field']['id']); + } + + /** + * Tests additional edit links. + */ + public function testEntityLinksJustEditForm() { + $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit'); + + $data = $this->viewsData->getViewsData(); + $this->assertFalse(isset($data['entity_test']['view_entity_test'])); + $this->assertFalse(isset($data['entity_test']['delete_entity_test'])); + + $this->assertEquals('entity_link_edit', $data['entity_test']['edit_entity_test']['field']['id']); + } + + /** * Tests views data for a string field. * * @param $data