diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module index a04e99d..5f94719 100644 --- a/core/modules/content_moderation/content_moderation.module +++ b/core/modules/content_moderation/content_moderation.module @@ -45,7 +45,8 @@ function _content_moderation_create_entity_type_info() { return new EntityTypeInfo( \Drupal::service('string_translation'), \Drupal::service('content_moderation.moderation_information'), - \Drupal::service('entity_type.manager') + \Drupal::service('entity_type.manager'), + \Drupal::service('current_user') ); } diff --git a/core/modules/content_moderation/content_moderation.services.yml b/core/modules/content_moderation/content_moderation.services.yml index 02008ea..75f0c64 100644 --- a/core/modules/content_moderation/content_moderation.services.yml +++ b/core/modules/content_moderation/content_moderation.services.yml @@ -9,7 +9,7 @@ services: arguments: ['@entity_type.manager', '@entity.query'] content_moderation.moderation_information: class: Drupal\content_moderation\ModerationInformation - arguments: ['@entity_type.manager', '@current_user'] + arguments: ['@entity_type.manager'] access_check.latest_revision: class: Drupal\content_moderation\Access\LatestRevisionCheck arguments: ['@content_moderation.moderation_information'] diff --git a/core/modules/content_moderation/src/EntityTypeInfo.php b/core/modules/content_moderation/src/EntityTypeInfo.php index 1e2497d..a7aa4d9 100644 --- a/core/modules/content_moderation/src/EntityTypeInfo.php +++ b/core/modules/content_moderation/src/EntityTypeInfo.php @@ -10,6 +10,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\Url; @@ -45,6 +46,13 @@ class EntityTypeInfo { protected $entityTypeManager; /** + * The current user. + * + * @var \Drupal\Core\Session\AccountInterface + */ + protected $currentUser; + + /** * A keyed array of custom moderation handlers for given entity types. * * Any entity not specified will use a common default. @@ -66,10 +74,11 @@ class EntityTypeInfo { * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * Entity type manager. */ - public function __construct(TranslationInterface $translation, ModerationInformationInterface $moderation_information, EntityTypeManagerInterface $entity_type_manager) { + public function __construct(TranslationInterface $translation, ModerationInformationInterface $moderation_information, EntityTypeManagerInterface $entity_type_manager, AccountInterface $current_user) { $this->stringTranslation = $translation; $this->moderationInfo = $moderation_information; $this->entityTypeManager = $entity_type_manager; + $this->currentUser = $current_user; } /** @@ -83,7 +92,7 @@ public function __construct(TranslationInterface $translation, ModerationInforma * @see hook_entity_type_alter() */ public function entityTypeAlter(array &$entity_types) { - foreach ($this->moderationInfo->selectRevisionableEntityTypes($entity_types) as $type_name => $type) { + foreach ($this->filterNonRevisionableEntityTypes($entity_types) as $type_name => $type) { $entity_types[$type_name] = $this->addModerationToEntityType($type); $entity_types[$type->get('bundle_of')] = $this->addModerationToEntity($entity_types[$type->get('bundle_of')]); } @@ -169,8 +178,10 @@ protected function addModerationToEntityType(ConfigEntityTypeInterface $type) { public function entityOperation(EntityInterface $entity) { $operations = []; $type = $entity->getEntityType(); - - if ($this->moderationInfo->shouldModerateEntities($entity->getEntityType(), $entity->bundle())) { + $bundle_of = $type->getBundleOf(); + if ($this->currentUser->hasPermission('administer moderation states') && $bundle_of && + $this->moderationInfo->canModerateEntitiesOfEntityType($this->entityTypeManager->getDefinition($bundle_of)) + ) { $operations['manage-moderation'] = [ 'title' => t('Manage moderation'), 'weight' => 27, @@ -234,9 +245,8 @@ public function entityExtraFieldInfo() { * - bundle: The machine name of a bundle, such as "page" or "article". */ protected function getModeratedBundles() { - $revisionable_types = $this->moderationInfo->selectRevisionableEntityTypes($this->entityTypeManager->getDefinitions()); /** @var ConfigEntityTypeInterface $type */ - foreach ($revisionable_types as $type_name => $type) { + foreach ($this->filterNonRevisionableEntityTypes($this->entityTypeManager->getDefinitions()) as $type_name => $type) { $result = $this->entityTypeManager ->getStorage($type_name) ->getQuery() @@ -259,7 +269,7 @@ protected function getModeratedBundles() { * New fields added by moderation state. */ public function entityBaseFieldInfo(EntityTypeInterface $entity_type) { - if (!$this->moderationInfo->canModerateEntityType($entity_type)) { + if (!$this->moderationInfo->canModerateEntitiesOfEntityType($entity_type)) { return []; } @@ -301,7 +311,7 @@ public function entityBaseFieldInfo(EntityTypeInterface $entity_type) { * @see hook_entity_bundle_field_info_alter(); */ public function entityBundleFieldInfoAlter(&$fields, EntityTypeInterface $entity_type, $bundle) { - if (!empty($fields['moderation_state']) && $this->moderationInfo->shouldModerateEntities($entity_type, $bundle)) { + if (!empty($fields['moderation_state']) && $this->moderationInfo->shouldModerateEntitiesOfBundle($entity_type, $bundle)) { $fields['moderation_state']->addConstraint('ModerationState', []); } } @@ -358,4 +368,21 @@ public static function bundleFormRedirect(array &$form, FormStateInterface $form } } + /** + * Filters entity type lists to return only revisionable entity types. + * + * @param EntityTypeInterface[] $entity_types + * The master entity type list filter. + * + * @return \Drupal\Core\Config\Entity\ConfigEntityTypeInterface[] + * An array of revisionable entity types which are configuration entities. + */ + protected function filterNonRevisionableEntityTypes(array $entity_types) { + return array_filter($entity_types, function (EntityTypeInterface $type) use ($entity_types) { + return ($type instanceof ConfigEntityTypeInterface) + && ($bundle_of = $type->get('bundle_of')) + && $entity_types[$bundle_of]->isRevisionable(); + }); + } + } diff --git a/core/modules/content_moderation/src/ModerationInformation.php b/core/modules/content_moderation/src/ModerationInformation.php index 6a7b939..331955e 100644 --- a/core/modules/content_moderation/src/ModerationInformation.php +++ b/core/modules/content_moderation/src/ModerationInformation.php @@ -2,16 +2,13 @@ namespace Drupal\content_moderation; -use Drupal\Core\Config\Entity\ConfigEntityTypeInterface; use Drupal\Core\Entity\BundleEntityFormBase; use Drupal\Core\Entity\ContentEntityFormInterface; use Drupal\Core\Entity\ContentEntityInterface; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormInterface; -use Drupal\Core\Session\AccountInterface; /** * General service for moderation-related questions about Entity API. @@ -26,13 +23,6 @@ class ModerationInformation implements ModerationInformationInterface { protected $entityTypeManager; /** - * The current user. - * - * @var \Drupal\Core\Session\AccountInterface - */ - protected $currentUser; - - /** * Creates a new ModerationInformation instance. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager @@ -40,9 +30,8 @@ class ModerationInformation implements ModerationInformationInterface { * @param \Drupal\Core\Session\AccountInterface $current_user * The current user. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager, AccountInterface $current_user) { + public function __construct(EntityTypeManagerInterface $entity_type_manager) { $this->entityTypeManager = $entity_type_manager; - $this->currentUser = $current_user; } /** @@ -53,13 +42,13 @@ public function isModeratedEntity(EntityInterface $entity) { return FALSE; } - return $this->shouldModerateEntities($entity->getEntityType(), $entity->bundle()); + return $this->shouldModerateEntitiesOfBundle($entity->getEntityType(), $entity->bundle()); } /** * {@inheritdoc} */ - public function canModerateEntityType(EntityTypeInterface $entity_type) { + public function canModerateEntitiesOfEntityType(EntityTypeInterface $entity_type) { return $entity_type->hasHandlerClass('moderation'); } @@ -75,7 +64,7 @@ public function loadBundleEntity($bundle_entity_type_id, $bundle_id) { /** * {@inheritdoc} */ - public function shouldModerateEntities(EntityTypeInterface $entity_type, $bundle) { + public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type, $bundle) { if ($bundle_entity = $this->loadBundleEntity($entity_type->getBundleEntityType(), $bundle)) { return $bundle_entity->getThirdPartySetting('content_moderation', 'enabled', FALSE); } @@ -85,28 +74,6 @@ public function shouldModerateEntities(EntityTypeInterface $entity_type, $bundle /** * {@inheritdoc} */ - public function selectRevisionableEntityTypes(array $entity_types) { - return array_filter($entity_types, function (EntityTypeInterface $type) use ($entity_types) { - return ($type instanceof ConfigEntityTypeInterface) - && ($bundle_of = $type->get('bundle_of')) - && $entity_types[$bundle_of]->isRevisionable(); - }); - } - - /** - * {@inheritdoc} - */ - public function selectRevisionableEntities(array $entity_types) { - return array_filter($entity_types, function (EntityTypeInterface $type) use ($entity_types) { - return ($type instanceof ContentEntityTypeInterface) - && $type->isRevisionable() - && $type->getBundleEntityType(); - }); - } - - /** - * {@inheritdoc} - */ public function isModeratedEntityForm(FormInterface $form_object) { return $form_object instanceof ContentEntityFormInterface && $this->isModeratedEntity($form_object->getEntity()); diff --git a/core/modules/content_moderation/src/ModerationInformationInterface.php b/core/modules/content_moderation/src/ModerationInformationInterface.php index 9c53605..10a5567 100644 --- a/core/modules/content_moderation/src/ModerationInformationInterface.php +++ b/core/modules/content_moderation/src/ModerationInformationInterface.php @@ -37,15 +37,15 @@ public function loadBundleEntity($bundle_entity_type_id, $bundle_id); public function isModeratedEntity(EntityInterface $entity); /** - * Determines if an entity type can be moderated. + * Determines if an entity type can have moderated entities. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type * An entity type object. * * @return bool - * TRUE if this entity type is moderated, FALSE otherwise. + * TRUE if this entity type can have moderated entities, FALSE otherwise. */ - public function canModerateEntityType(EntityTypeInterface $entity_type); + public function canModerateEntitiesOfEntityType(EntityTypeInterface $entity_type); /** * Determines if an entity type/bundle entities should be moderated. @@ -59,32 +59,7 @@ public function canModerateEntityType(EntityTypeInterface $entity_type); * TRUE if an entity type/bundle entities should be moderated, FALSE * otherwise. */ - public function shouldModerateEntities(EntityTypeInterface $entity_type, $bundle); - - /** - * Filters entity lists to just bundle definitions for revisionable entities. - * - * @param EntityTypeInterface[] $entity_types - * The master entity type list filter. - * - * @return \Drupal\Core\Config\Entity\ConfigEntityTypeInterface[] - * An array of only the config entities we want to modify. - */ - public function selectRevisionableEntityTypes(array $entity_types); - - /** - * Filters entity lists to just the definitions that can be moderated. - * - * An entity type can be moderated only if it is both revisionable and - * bundleable. - * - * @param EntityTypeInterface[] $entity_types - * The master entity type list filter. - * - * @return \Drupal\Core\Entity\ContentEntityTypeInterface[] - * An array of only the content entity definitions that can be moderated. - */ - public function selectRevisionableEntities(array $entity_types); + public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type, $bundle); /** * Determines if this form is for a moderated entity. diff --git a/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php b/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php index bdfba0b..84ad4aa 100644 --- a/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php +++ b/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php @@ -76,22 +76,21 @@ public static function create(ContainerInterface $container, $base_plugin_id) { public function getDerivativeDefinitions($base_plugin_definition) { $this->derivatives = []; - foreach ($this->moderationInfo->selectRevisionableEntityTypes($this->entityTypeManager->getDefinitions()) as $entity_type_id => $entity_type) { - $this->derivatives["$entity_type_id.moderation_tab"] = [ - 'route_name' => "entity.$entity_type_id.moderation", - 'title' => $this->t('Manage moderation'), - // @todo - are we sure they all have an edit_form? - 'base_route' => "entity.$entity_type_id.edit_form", - 'weight' => 30, - ] + $base_plugin_definition; + foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { + if ($this->moderationInfo->canModerateEntitiesOfEntityType($entity_type)) { + $this->derivatives["$entity_type_id.moderation_tab"] = [ + 'route_name' => "entity.$entity_type_id.moderation", + 'title' => $this->t('Manage moderation'), + // @todo - are we sure they all have an edit_form? + 'base_route' => "entity.$entity_type_id.edit_form", + 'weight' => 30, + ] + $base_plugin_definition; + } } - $latest_version_entities = array_filter( - $this->moderationInfo->selectRevisionableEntities($this->entityTypeManager->getDefinitions()), - function (EntityTypeInterface $type) { - return $type->hasLinkTemplate('latest-version'); - } - ); + $latest_version_entities = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $type) { + return $this->moderationInfo->canModerateEntitiesOfEntityType($type) && $type->hasLinkTemplate('latest-version'); + }); foreach ($latest_version_entities as $entity_type_id => $entity_type) { $this->derivatives["$entity_type_id.latest_version_tab"] = [ diff --git a/core/modules/content_moderation/src/ViewsData.php b/core/modules/content_moderation/src/ViewsData.php index cad1187..19bcfa5 100644 --- a/core/modules/content_moderation/src/ViewsData.php +++ b/core/modules/content_moderation/src/ViewsData.php @@ -115,8 +115,12 @@ public function getViewsData() { ], ]; + $entity_types_with_moderation = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $type) { + return $this->moderationInformation->canModerateEntitiesOfEntityType($type); + }); + // Add a join for each entity type to the content_revision_tracker table. - foreach ($this->moderationInformation->selectRevisionableEntities($this->entityTypeManager->getDefinitions()) as $entity_type_id => $entity_type) { + foreach ($entity_types_with_moderation as $entity_type_id => $entity_type) { /** @var \Drupal\views\EntityViewsDataInterface $views_data */ // We need the views_data handler in order to get the table name later. if ($this->entityTypeManager->hasHandler($entity_type_id, 'views_data') && $views_data = $this->entityTypeManager->getHandler($entity_type_id, 'views_data')) { @@ -178,7 +182,7 @@ public function getViewsData() { $content_moderation_state_entity_type = \Drupal::entityTypeManager()->getDefinition('content_moderation_state'); $content_moderation_state_entity_base_table = $content_moderation_state_entity_type->getDataTable() ?: $content_moderation_state_entity_type->getBaseTable(); $content_moderation_state_entity_revision_base_table = $content_moderation_state_entity_type->getRevisionDataTable() ?: $content_moderation_state_entity_type->getRevisionTable(); - foreach ($this->moderationInformation->selectRevisionableEntities($this->entityTypeManager->getDefinitions()) as $entity_type_id => $entity_type) { + foreach ($entity_types_with_moderation as $entity_type_id => $entity_type) { $table = $entity_type->getDataTable() ?: $entity_type->getBaseTable(); $data[$table]['moderation_state'] = [ @@ -234,8 +238,10 @@ public function getViewsData() { * @see hook_views_data() */ public function alterViewsData(array &$data) { - $revisionable_types = $this->moderationInformation->selectRevisionableEntities($this->entityTypeManager->getDefinitions()); - foreach ($revisionable_types as $type) { + $entity_types_with_moderation = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $type) { + return $this->moderationInformation->canModerateEntitiesOfEntityType($type); + }); + foreach ($entity_types_with_moderation as $type) { $data[$type->getRevisionTable()]['latest_revision'] = [ 'title' => t('Is Latest Revision'), 'help' => t('Restrict the view to only revisions that are the latest revision of their entity.'), diff --git a/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php b/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php index 30b0c7f..969b815 100644 --- a/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php +++ b/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php @@ -100,9 +100,9 @@ public function testIsModeratedEntityForNonBundleEntityType() { /** * @dataProvider providerBoolean - * @covers ::shouldModerateEntities + * @covers ::shouldModerateEntitiesOfBundle */ - public function testIsModeratedBundle($status) { + public function testShouldModerateEntities($status) { $entity_type = new ContentEntityType([ 'id' => 'test_entity_type', 'bundle_entity_type' => 'entity_test_bundle', @@ -110,7 +110,7 @@ public function testIsModeratedBundle($status) { $moderation_information = new ModerationInformation($this->setupModerationEntityManager($status), $this->getUser()); - $this->assertEquals($status, $moderation_information->shouldModerateEntities($entity_type, 'test_bundle')); + $this->assertEquals($status, $moderation_information->shouldModerateEntitiesOfBundle($entity_type, 'test_bundle')); } /**