diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 51472cf8c5..6928f17efd 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -7,11 +7,14 @@
use Drupal\comment\CommentInterface;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
+use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\taxonomy\TermInterface;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\user\Entity\User;
@@ -349,6 +352,22 @@ function forum_form_node_form_alter(&$form, FormStateInterface $form_state, $for
}
/**
+ * Implements hook_ENTITY_TYPE_access() for taxonomy_term.
+ */
+function forum_taxonomy_term_access(TermInterface $term, $operation, AccountInterface $account) {
+ // Allow update access to terms in the forum vocabulary with the
+ // administer forums permission.
+ $forum_vid = \Drupal::config('forum.settings')->get('vocabulary');
+ if ($operation ==='update' && $term->bundle() === $forum_vid) {
+ return AccessResult::allowedIfHasPermission($account, 'administer forums');
+ }
+
+ // No opinion.
+ return AccessResult::neutral();
+}
+
+
+/**
* Implements hook_preprocess_HOOK() for block templates.
*/
function forum_preprocess_block(&$variables) {
diff --git a/core/modules/forum/src/Form/Overview.php b/core/modules/forum/src/Form/Overview.php
index 08d37787bd..8c374b5842 100644
--- a/core/modules/forum/src/Form/Overview.php
+++ b/core/modules/forum/src/Form/Overview.php
@@ -58,13 +58,14 @@ public function buildForm(array $form, FormStateInterface $form_state) {
foreach (Element::children($form['terms']) as $key) {
if (isset($form['terms'][$key]['#term'])) {
+ /** @var \Drupal\taxonomy\TermInterface $term */
$term = $form['terms'][$key]['#term'];
$form['terms'][$key]['term']['#url'] = Url::fromRoute('forum.page', ['taxonomy_term' => $term->id()]);
- if ($form['terms'][$key]['#term']->access('delete')) {
+ if ($term->access('delete')) {
unset($form['terms'][$key]['operations']['#links']['delete']);
}
- if ($form['terms'][$key]['#term']->access('update')) {
+ if ($term->access('update')) {
$route_parameters = $form['terms'][$key]['operations']['#links']['edit']['url']->getRouteParameters();
if (!empty($term->forum_container->value)) {
$form['terms'][$key]['operations']['#links']['edit']['title'] = $this->t('edit container');
diff --git a/core/modules/forum/tests/src/Functional/ForumIndexTest.php b/core/modules/forum/tests/src/Functional/ForumIndexTest.php
index 38adb72ea8..4b048e2647 100644
--- a/core/modules/forum/tests/src/Functional/ForumIndexTest.php
+++ b/core/modules/forum/tests/src/Functional/ForumIndexTest.php
@@ -57,6 +57,8 @@ public function testForumIndexStatus() {
'parent[0]' => $tid,
];
$this->drupalPostForm('admin/structure/forum/add/forum', $edit, t('Save'));
+ $this->assertSession()->linkExists(t('edit forum'), 0, 'edit forum link is not accessible to user with administer forums permission');
+
$tid_child = $tid + 1;
// Verify that the node appears on the index.
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Term/TermResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermResourceTestBase.php
index 1a4d4498a5..b13250faaa 100644
--- a/core/modules/rest/tests/src/Functional/EntityResource/Term/TermResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Term/TermResourceTestBase.php
@@ -45,14 +45,14 @@ protected function setUpAuthorization($method) {
$this->grantPermissionsToTestedRole(['create terms in camelids']);
break;
case 'PATCH':
- $this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
- break;
- case 'DELETE':
// Grant the 'create url aliases' permission to test the case when
// the path field is accessible, see
// \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase
// for a negative test.
- $this->grantPermissionsToTestedRole(['delete terms in camelids', 'create url aliases']);
+ $this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
+ break;
+ case 'DELETE':
+ $this->grantPermissionsToTestedRole(['delete terms in camelids']);
break;
}
}
diff --git a/core/modules/taxonomy/src/Access/TaxonomyOverviewAccessCheck.php b/core/modules/taxonomy/src/Access/TaxonomyOverviewAccessCheck.php
deleted file mode 100644
index cd9065bb6f..0000000000
--- a/core/modules/taxonomy/src/Access/TaxonomyOverviewAccessCheck.php
+++ /dev/null
@@ -1,25 +0,0 @@
-hasPermission('administer taxonomy') || $account->hasPermission('access taxonomy overview');
- return AccessResult::allowedIf($access);
- }
-
-}
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index 03491ab962..c28a379d09 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -20,6 +20,7 @@
* "storage" = "Drupal\taxonomy\TermStorage",
* "storage_schema" = "Drupal\taxonomy\TermStorageSchema",
* "view_builder" = "Drupal\taxonomy\TermViewBuilder",
+ * "list_builder" = "Drupal\taxonomy\TermListBuilder",
* "access" = "Drupal\taxonomy\TermAccessControlHandler",
* "views_data" = "Drupal\taxonomy\TermViewsData",
* "form" = {
diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php
index b0d1ac13d2..d61294b4e3 100644
--- a/core/modules/taxonomy/src/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/src/Entity/Vocabulary.php
@@ -15,6 +15,7 @@
* handlers = {
* "storage" = "Drupal\taxonomy\VocabularyStorage",
* "list_builder" = "Drupal\taxonomy\VocabularyListBuilder",
+ * "access" = "Drupal\taxonomy\VocabularyAccessControlHandler",
* "form" = {
* "default" = "Drupal\taxonomy\VocabularyForm",
* "reset" = "Drupal\taxonomy\Form\VocabularyResetForm",
diff --git a/core/modules/taxonomy/src/Form/OverviewTerms.php b/core/modules/taxonomy/src/Form/OverviewTerms.php
index 8c4b64c178..e4209ebffd 100644
--- a/core/modules/taxonomy/src/Form/OverviewTerms.php
+++ b/core/modules/taxonomy/src/Form/OverviewTerms.php
@@ -6,6 +6,7 @@
use Drupal\Core\Form\FormBase;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
use Drupal\taxonomy\VocabularyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -36,6 +37,13 @@ class OverviewTerms extends FormBase {
protected $storageController;
/**
+ * The term list builder.
+ *
+ * @var \Drupal\Core\Entity\EntityListBuilderInterface
+ */
+ protected $termListBuilder;
+
+ /**
* Constructs an OverviewTerms object.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
@@ -47,6 +55,7 @@ public function __construct(ModuleHandlerInterface $module_handler, EntityManage
$this->moduleHandler = $module_handler;
$this->entityManager = $entity_manager;
$this->storageController = $entity_manager->getStorage('taxonomy_term');
+ $this->termListBuilder = $entity_manager->getListBuilder('taxonomy_term');
}
/**
@@ -204,12 +213,11 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
}
$errors = $form_state->getErrors();
- $destination = $this->getDestinationArray();
$row_position = 0;
// Build the actual form.
$access_control_handler = $this->entityManager->getAccessControlHandler('taxonomy_term');
if ($access_control_handler->createAccess($taxonomy_vocabulary->id())) {
- $empty = $this->t('No terms available. Add term.', ['@link' => $this->url('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $taxonomy_vocabulary->id()])]);
+ $empty = $this->t('No terms available. Add term.', ['@link' => Url::fromRoute('entity.taxonomy_term.add_form', ['taxonomy_vocabulary' => $taxonomy_vocabulary->id()])->toString()]);
}
else {
$empty = $this->t('No terms available.');
@@ -222,7 +230,7 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
],
];
$change_weight_access = TRUE;
- $operations_access = TRUE;
+ $operations_access = FALSE;
foreach ($current_page as $key => $term) {
/** @var $term \Drupal\Core\Entity\EntityInterface */
$term = $this->entityManager->getTranslationFromContext($term);
@@ -282,35 +290,14 @@ public function buildForm(array $form, FormStateInterface $form_state, Vocabular
'#access' => $edit_access,
];
}
- $operations = [];
- if ($edit_access) {
- $operations['edit'] = [
- 'title' => $this->t('Edit'),
- 'query' => $destination,
- 'url' => $term->urlInfo('edit-form'),
- ];
- }
- if ($term->access('delete')) {
- $operations['delete'] = [
- 'title' => $this->t('Delete'),
- 'query' => $destination,
- 'url' => $term->urlInfo('delete-form'),
- ];
- }
- if ($this->moduleHandler->moduleExists('content_translation') && content_translation_translate_access($term)->isAllowed()) {
- $operations['translate'] = [
- 'title' => $this->t('Translate'),
- 'query' => $destination,
- 'url' => $term->urlInfo('drupal:content-translation-overview'),
- ];
- }
-
- $operations_access &= count($operations) > 0;
- if (count($operations)) {
+ if ($operations = $this->termListBuilder->getOperations($term)) {
+ // Allow access to operations if there is at least one term with
+ // operations.
+ $operations_access = TRUE;
$form['terms'][$key]['operations'] = [
'#type' => 'operations',
- '#links' => $operations,
+ '#links' => $operations
];
}
diff --git a/core/modules/taxonomy/src/TermListBuilder.php b/core/modules/taxonomy/src/TermListBuilder.php
new file mode 100644
index 0000000000..0d691e194b
--- /dev/null
+++ b/core/modules/taxonomy/src/TermListBuilder.php
@@ -0,0 +1,64 @@
+get('entity_type.manager')->getStorage($entity_type->id()),
+ $container->get('redirect.destination')
+ );
+ }
+
+ /**
+ * Constructs a new instance.
+ *
+ * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+ * The entity type definition.
+ * @param \Drupal\Core\Entity\EntityStorageInterface $storage
+ * The entity storage class.
+ * @param \Drupal\Core\Routing\RedirectDestinationInterface
+ * The redirect destination.
+ */
+ public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, RedirectDestinationInterface $redirect_destination) {
+ parent::__construct($entity_type, $storage);
+
+ $this->redirectDestination = $redirect_destination;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultOperations(EntityInterface $entity) {
+ $operations = parent::getDefaultOperations($entity);
+
+ $destination = $this->redirectDestination->get();
+ foreach ($operations as $key => $operation) {
+ $operations[$key]['query']['destination'] = $destination;
+ }
+
+ return $operations;
+ }
+}
diff --git a/core/modules/taxonomy/src/VocabularyAccessControlHandler.php b/core/modules/taxonomy/src/VocabularyAccessControlHandler.php
new file mode 100644
index 0000000000..befc8a5fdf
--- /dev/null
+++ b/core/modules/taxonomy/src/VocabularyAccessControlHandler.php
@@ -0,0 +1,30 @@
+getStorage($entity_type->id()));
- $this->current_user = $current_user;
- $this->entityManager = $entity_manager;
- $this->access_view = $access_view;
+ $this->currentUser = $current_user;
+ $this->entityTypeManager = $entity_type_manager;
}
/**
@@ -67,10 +60,8 @@ public function __construct(EntityTypeInterface $entity_type, EntityStorageInter
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$entity_type,
- $container->get('entity.manager')->getStorage($entity_type->id()),
$container->get('current_user'),
- $container->get('entity.manager'),
- $container->get('access_check.taxonomy.taxonomy_overview')
+ $container->get('entity_type.manager')
);
}
@@ -91,15 +82,15 @@ public function getDefaultOperations(EntityInterface $entity) {
$operations['edit']['title'] = t('Edit vocabulary');
}
- if ($this->access_view->access($this->current_user)) {
+ if ($entity->access('access taxonomy overview')) {
$operations['list'] = [
'title' => t('List terms'),
'weight' => 0,
- 'url' => $entity->urlInfo('overview-form'),
+ 'url' => $entity->toUrl('overview-form'),
];
}
- $taxonomy_term_access_control_handler = $this->entityManager->getAccessControlHandler('taxonomy_term');
+ $taxonomy_term_access_control_handler = $this->entityTypeManager->getAccessControlHandler('taxonomy_term');
if ($taxonomy_term_access_control_handler->createAccess($entity->id())) {
$operations['add'] = [
'title' => t('Add terms'),
@@ -120,7 +111,7 @@ public function buildHeader() {
$header['label'] = t('Vocabulary name');
$header['description'] = t('Description');
- if ($this->current_user->hasPermission('administer vocabularies')) {
+ if ($this->currentUser->hasPermission('administer vocabularies')) {
$header['weight'] = t('Weight');
}
@@ -147,8 +138,9 @@ public function render() {
unset($this->weightKey);
}
$build = parent::render();
- if ($this->current_user->hasPermission('administer vocabularies')) {
- $build['table']['#empty'] = t('No vocabularies available. Add vocabulary.', ['@link' => \Drupal::url('entity.taxonomy_vocabulary.add_form')]);
+ $create_access = $this->entityTypeManager->getAccessControlHandler('taxonomy_vocabulary')->createAccess();
+ if ($create_access) {
+ $build['table']['#empty'] = t('No vocabularies available. Add vocabulary.', ['@link' => Url::fromRoute('entity.taxonomy_vocabulary.add_form')->toString()]);
}
else {
$build['table']['#empty'] = t('No vocabularies available.');
diff --git a/core/modules/taxonomy/taxonomy.routing.yml b/core/modules/taxonomy/taxonomy.routing.yml
index 94c8727768..19989241e4 100644
--- a/core/modules/taxonomy/taxonomy.routing.yml
+++ b/core/modules/taxonomy/taxonomy.routing.yml
@@ -74,7 +74,7 @@ entity.taxonomy_vocabulary.overview_form:
_form: 'Drupal\taxonomy\Form\OverviewTerms'
_title_callback: 'Drupal\taxonomy\Controller\TaxonomyController::vocabularyTitle'
requirements:
- _permission: 'access taxonomy overview+administer taxonomy'
+ _entity_access: 'taxonomy_vocabulary.access taxonomy overview'
entity.taxonomy_term.canonical:
path: '/taxonomy/term/{taxonomy_term}'
diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml
index b521c7f596..a8153ed117 100644
--- a/core/modules/taxonomy/taxonomy.services.yml
+++ b/core/modules/taxonomy/taxonomy.services.yml
@@ -4,7 +4,3 @@ services:
arguments: ['@entity.manager']
tags:
- { name: breadcrumb_builder, priority: 1002 }
- access_check.taxonomy.taxonomy_overview:
- class: Drupal\taxonomy\Access\TaxonomyOverviewAccessCheck
- tags:
- - { name: access_check, applies_to: _access_taxonomy_overview }