diff --git a/core/modules/content_moderation/src/EntityOperations.php b/core/modules/content_moderation/src/EntityOperations.php index 3f66100..9761899 100644 --- a/core/modules/content_moderation/src/EntityOperations.php +++ b/core/modules/content_moderation/src/EntityOperations.php @@ -110,7 +110,7 @@ public function entityPresave(EntityInterface $entity) { $update_default_revision = $entity->isNew() || $entity->isNewTranslation() || $current_state->isDefaultRevisionState() - || !$this->isDefaultRevisionPublished($entity, $workflow); + || !$this->moderationInfo->isDefaultRevisionPublished($entity); // Fire per-entity-type logic for handling the save process. $this->entityTypeManager->getHandler($entity->getEntityTypeId(), 'moderation')->onPresave($entity, $update_default_revision, $current_state->isPublishedState()); @@ -247,38 +247,4 @@ public function entityView(array &$build, EntityInterface $entity, EntityViewDis } } - /** - * Check if the default revision for the given entity is published. - * - * The default revision is the same as the entity retrieved by "default" from - * the storage handler. If the entity is translated, check if any of the - * translations are published. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity being saved. - * @param \Drupal\workflows\WorkflowInterface $workflow - * The workflow being applied to the entity. - * - * @return bool - * TRUE if the default revision is published. FALSE otherwise. - */ - protected function isDefaultRevisionPublished(EntityInterface $entity, WorkflowInterface $workflow) { - $default_revision = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->load($entity->id()); - - // Ensure we are checking all translations of the default revision. - if ($default_revision instanceof TranslatableInterface && $default_revision->isTranslatable()) { - // Loop through each language that has a translation. - foreach ($default_revision->getTranslationLanguages() as $language) { - // Load the translated revision. - $language_revision = $default_revision->getTranslation($language->getId()); - // Return TRUE if a translation with a published state is found. - if ($workflow->getState($language_revision->moderation_state->value)->isPublishedState()) { - return TRUE; - } - } - } - - return $workflow->getState($default_revision->moderation_state->value)->isPublishedState(); - } - } diff --git a/core/modules/content_moderation/src/ModerationInformation.php b/core/modules/content_moderation/src/ModerationInformation.php index c20be52..1294bc1 100644 --- a/core/modules/content_moderation/src/ModerationInformation.php +++ b/core/modules/content_moderation/src/ModerationInformation.php @@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityTypeBundleInfoInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\TypedData\TranslatableInterface; /** * General service for moderation-related questions about Entity API. @@ -140,6 +141,29 @@ public function isLiveRevision(ContentEntityInterface $entity) { /** * {@inheritdoc} */ + public function isDefaultRevisionPublished(ContentEntityInterface $entity) { + $workflow = $this->getWorkflowForEntity($entity); + $default_revision = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId())->load($entity->id()); + + // Ensure we are checking all translations of the default revision. + if ($default_revision instanceof TranslatableInterface && $default_revision->isTranslatable()) { + // Loop through each language that has a translation. + foreach ($default_revision->getTranslationLanguages() as $language) { + // Load the translated revision. + $language_revision = $default_revision->getTranslation($language->getId()); + // Return TRUE if a translation with a published state is found. + if ($workflow->getState($language_revision->moderation_state->value)->isPublishedState()) { + return TRUE; + } + } + } + + return $workflow->getState($default_revision->moderation_state->value)->isPublishedState(); + } + + /** + * {@inheritdoc} + */ public function getWorkflowForEntity(ContentEntityInterface $entity) { $bundles = $this->bundleInfo->getBundleInfo($entity->getEntityTypeId()); if (isset($bundles[$entity->bundle()]['workflow'])) { diff --git a/core/modules/content_moderation/src/ModerationInformationInterface.php b/core/modules/content_moderation/src/ModerationInformationInterface.php index 862987f..cf3adce 100644 --- a/core/modules/content_moderation/src/ModerationInformationInterface.php +++ b/core/modules/content_moderation/src/ModerationInformationInterface.php @@ -127,6 +127,21 @@ public function hasForwardRevision(ContentEntityInterface $entity); public function isLiveRevision(ContentEntityInterface $entity); /** + * Determines if the default revision for the given entity is published. + * + * The default revision is the same as the entity retrieved by "default" from + * the storage handler. If the entity is translated, check if any of the + * translations are published. + * + * @param \Drupal\Core\Entity\ContentEntityInterface $entity + * The entity being saved. + * + * @return bool + * TRUE if the default revision is published. FALSE otherwise. + */ + public function isDefaultRevisionPublished(ContentEntityInterface $entity); + + /** * Gets the workflow for the given content entity. * * @param \Drupal\Core\Entity\ContentEntityInterface $entity diff --git a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php index 2d93f5a..e2955b0 100644 --- a/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php +++ b/core/modules/content_moderation/src/Plugin/Field/ModerationStateFieldItemList.php @@ -3,6 +3,7 @@ namespace Drupal\content_moderation\Plugin\Field; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Field\FieldItemList; /** @@ -117,4 +118,41 @@ protected function computeModerationFieldItemList() { } } + /** + * {@inheritdoc} + */ + public function onChange($delta) { + $entity = $this->getEntity(); + + /** @var \Drupal\content_moderation\ModerationInformationInterface $content_moderation_info */ + $content_moderation_info = \Drupal::service('content_moderation.moderation_information'); + $workflow = $content_moderation_info->getWorkflowForEntity($entity); + + $current_state_id = $this->list[0]->value; + + // Change the entity's default revision flag and the publishing status only + // if the new workflow state is a valid one. + if ($workflow->hasState($current_state_id)) { + /** @var \Drupal\content_moderation\ContentModerationState $current_state */ + $current_state = $workflow->getState($current_state_id); + + // This entity is default if it is new, a new translation, the default + // revision state, or the default revision is not published. + $update_default_revision = $entity->isNew() + || $entity->isNewTranslation() + || $current_state->isDefaultRevisionState() + || !$content_moderation_info->isDefaultRevisionPublished($entity); + + $entity->isDefaultRevision($update_default_revision); + + // Update publishing status if it can be updated and if it needs updating. + $published_state = $current_state->isPublishedState(); + if (($entity instanceof EntityPublishedInterface) && $entity->isPublished() !== $published_state) { + $published_state ? $entity->setPublished() : $entity->setUnpublished(); + } + } + + parent::onChange($delta); + } + } diff --git a/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php b/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php index 5a2f6a0..a0d46da 100644 --- a/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php +++ b/core/modules/content_moderation/tests/src/Kernel/ModerationStateFieldItemListTest.php @@ -79,4 +79,24 @@ public function testArrayIteration() { $this->assertEquals(['draft'], $states); } + /** + * Tests that moderation state changes also change the related entity state. + */ + public function testModerationStateChanges() { + // Change the moderation state and check that the entity's + // 'isDefaultRevision' flag and the publishing status have also been + // updated. + $this->testNode->moderation_state->value = 'published'; + + $this->assertTrue($this->testNode->isPublished()); + $this->assertTrue($this->testNode->isDefaultRevision()); + + $this->testNode->save(); + + // Repeat the checks using an 'unpublished' state. + $this->testNode->moderation_state->value = 'draft'; + $this->assertFalse($this->testNode->isPublished()); + $this->assertFalse($this->testNode->isDefaultRevision()); + } + }