summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2017-08-10 07:16:25 (GMT)
committerNathaniel Catchpole2017-08-10 07:16:25 (GMT)
commite6f77992cdec3f037af2ffa54dca987344c0650d (patch)
tree51e5308533c070bdf7ab284d409c0b7363d0a347
parentbff6783e980edf0ae4877c8c4c64517ac54af4cd (diff)
Issue #2893888 by plach, Sam152, amateescu, evilehk: Content moderation state entity field data not removed when the host field data is
-rw-r--r--core/modules/content_moderation/content_moderation.module27
-rw-r--r--core/modules/content_moderation/src/Entity/ContentModerationState.php39
-rw-r--r--core/modules/content_moderation/src/EntityOperations.php87
-rw-r--r--core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php90
4 files changed, 218 insertions, 25 deletions
diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module
index 201fc45..09ade0d 100644
--- a/core/modules/content_moderation/content_moderation.module
+++ b/core/modules/content_moderation/content_moderation.module
@@ -92,6 +92,33 @@ function content_moderation_entity_update(EntityInterface $entity) {
}
/**
+ * Implements hook_entity_delete().
+ */
+function content_moderation_entity_delete(EntityInterface $entity) {
+ return \Drupal::service('class_resolver')
+ ->getInstanceFromDefinition(EntityOperations::class)
+ ->entityDelete($entity);
+}
+
+/**
+ * Implements hook_entity_revision_delete().
+ */
+function content_moderation_entity_revision_delete(EntityInterface $entity) {
+ return \Drupal::service('class_resolver')
+ ->getInstanceFromDefinition(EntityOperations::class)
+ ->entityRevisionDelete($entity);
+}
+
+/**
+ * Implements hook_entity_translation_delete().
+ */
+function content_moderation_entity_translation_delete(EntityInterface $translation) {
+ return \Drupal::service('class_resolver')
+ ->getInstanceFromDefinition(EntityOperations::class)
+ ->entityTranslationDelete($translation);
+}
+
+/**
* Implements hook_form_alter().
*/
function content_moderation_form_alter(&$form, FormStateInterface $form_state, $form_id) {
diff --git a/core/modules/content_moderation/src/Entity/ContentModerationState.php b/core/modules/content_moderation/src/Entity/ContentModerationState.php
index 39b0ff4..aedcb5f 100644
--- a/core/modules/content_moderation/src/Entity/ContentModerationState.php
+++ b/core/modules/content_moderation/src/Entity/ContentModerationState.php
@@ -4,6 +4,7 @@ namespace Drupal\content_moderation\Entity;
use Drupal\content_moderation\ContentModerationStateInterface;
use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\TypedData\TranslatableInterface;
@@ -143,6 +144,44 @@ class ContentModerationState extends ContentEntityBase implements ContentModerat
}
/**
+ * Loads a content moderation state entity.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * A moderated entity object.
+ *
+ * @return \Drupal\content_moderation\ContentModerationStateInterface|null
+ * The related content moderation state or NULL if none could be found.
+ *
+ * @internal
+ * This method should only be called by code directly handling the
+ * ContentModerationState entity objects.
+ */
+ public static function loadFromModeratedEntity(EntityInterface $entity) {
+ $content_moderation_state = NULL;
+ $moderation_info = \Drupal::service('content_moderation.moderation_information');
+
+ if ($moderation_info->isModeratedEntity($entity)) {
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ $storage = \Drupal::entityTypeManager()->getStorage('content_moderation_state');
+
+ $ids = $storage->getQuery()
+ ->condition('content_entity_type_id', $entity->getEntityTypeId())
+ ->condition('content_entity_id', $entity->id())
+ ->condition('workflow', $moderation_info->getWorkflowForEntity($entity)->id())
+ ->condition('content_entity_revision_id', $entity->getLoadedRevisionId())
+ ->allRevisions()
+ ->execute();
+
+ if ($ids) {
+ /** @var \Drupal\content_moderation\ContentModerationStateInterface $content_moderation_state */
+ $content_moderation_state = $storage->loadRevision(key($ids));
+ }
+ }
+
+ return $content_moderation_state;
+ }
+
+ /**
* Default value callback for the 'uid' base field definition.
*
* @see \Drupal\content_moderation\Entity\ContentModerationState::baseFieldDefinitions()
diff --git a/core/modules/content_moderation/src/EntityOperations.php b/core/modules/content_moderation/src/EntityOperations.php
index f726582..22e901b 100644
--- a/core/modules/content_moderation/src/EntityOperations.php
+++ b/core/modules/content_moderation/src/EntityOperations.php
@@ -154,31 +154,16 @@ class EntityOperations implements ContainerInjectionInterface {
* The entity to update or create a moderation state for.
*/
protected function updateOrCreateFromEntity(EntityInterface $entity) {
- $moderation_state = $entity->moderation_state->value;
- $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
- if (!$moderation_state) {
- $moderation_state = $workflow->getTypePlugin()->getInitialState($workflow, $entity)->id();
- }
-
- // @todo what if $entity->moderation_state is null at this point?
- $entity_type_id = $entity->getEntityTypeId();
- $entity_id = $entity->id();
$entity_revision_id = $entity->getRevisionId();
+ $workflow = $this->moderationInfo->getWorkflowForEntity($entity);
+ $content_moderation_state = ContentModerationStateEntity::loadFromModeratedEntity($entity);
- $storage = $this->entityTypeManager->getStorage('content_moderation_state');
- $entities = $storage->loadByProperties([
- 'content_entity_type_id' => $entity_type_id,
- 'content_entity_id' => $entity_id,
- 'workflow' => $workflow->id(),
- ]);
-
- /** @var \Drupal\content_moderation\ContentModerationStateInterface $content_moderation_state */
- $content_moderation_state = reset($entities);
if (!($content_moderation_state instanceof ContentModerationStateInterface)) {
+ $storage = $this->entityTypeManager->getStorage('content_moderation_state');
$content_moderation_state = $storage->create([
- 'content_entity_type_id' => $entity_type_id,
- 'content_entity_id' => $entity_id,
+ 'content_entity_type_id' => $entity->getEntityTypeId(),
+ 'content_entity_id' => $entity->id(),
// Make sure that the moderation state entity has the same language code
// as the moderated entity.
'langcode' => $entity->language()->getId(),
@@ -203,6 +188,13 @@ class EntityOperations implements ContainerInjectionInterface {
}
// Create the ContentModerationState entity for the inserted entity.
+ $moderation_state = $entity->moderation_state->value;
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ if (!$moderation_state) {
+ $moderation_state = $workflow->getTypePlugin()->getInitialState($workflow, $entity)->id();
+ }
+
+ // @todo what if $entity->moderation_state is null at this point?
$content_moderation_state->set('content_entity_revision_id', $entity_revision_id);
$content_moderation_state->set('moderation_state', $moderation_state);
ContentModerationStateEntity::updateOrCreateFromEntity($content_moderation_state);
@@ -225,6 +217,61 @@ class EntityOperations implements ContainerInjectionInterface {
}
/**
+ * Hook bridge.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * The entity being deleted.
+ *
+ * @see hook_entity_delete()
+ */
+ public function entityDelete(EntityInterface $entity) {
+ $content_moderation_state = ContentModerationStateEntity::loadFromModeratedEntity($entity);
+ if ($content_moderation_state) {
+ $content_moderation_state->delete();
+ }
+ }
+
+ /**
+ * Hook bridge.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ * The entity revision being deleted.
+ *
+ * @see hook_entity_revision_delete()
+ */
+ public function entityRevisionDelete(EntityInterface $entity) {
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ if (!$entity->isDefaultRevision()) {
+ $content_moderation_state = ContentModerationStateEntity::loadFromModeratedEntity($entity);
+ if ($content_moderation_state) {
+ $this->entityTypeManager
+ ->getStorage('content_moderation_state')
+ ->deleteRevision($content_moderation_state->getRevisionId());
+ }
+ }
+ }
+
+ /**
+ * Hook bridge.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $translation
+ * The entity translation being deleted.
+ *
+ * @see hook_entity_translation_delete()
+ */
+ public function entityTranslationDelete(EntityInterface $translation) {
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $translation */
+ if (!$translation->isDefaultTranslation()) {
+ $langcode = $translation->language()->getId();
+ $content_moderation_state = ContentModerationStateEntity::loadFromModeratedEntity($translation);
+ if ($content_moderation_state && $content_moderation_state->hasTranslation($langcode)) {
+ $content_moderation_state->removeTranslation($langcode);
+ ContentModerationStateEntity::updateOrCreateFromEntity($content_moderation_state);
+ }
+ }
+ }
+
+ /**
* Act on entities being assembled before rendering.
*
* This is a hook bridge.
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
index 713e5b5..5e237f3 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationStateTest.php
@@ -3,13 +3,13 @@
namespace Drupal\Tests\content_moderation\Kernel;
use Drupal\content_moderation\Entity\ContentModerationState;
+use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_test\Entity\EntityTestBundle;
use Drupal\entity_test\Entity\EntityTestRev;
use Drupal\entity_test\Entity\EntityTestWithBundle;
-use Drupal\Core\Entity\EntityInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
@@ -29,6 +29,7 @@ class ContentModerationStateTest extends KernelTestBase {
public static $modules = [
'entity_test',
'node',
+ 'block',
'block_content',
'media',
'media_test_source',
@@ -74,17 +75,20 @@ class ContentModerationStateTest extends KernelTestBase {
}
/**
- * Tests basic monolingual content moderation through the API.
+ * Sets up a bundle entity type for the specified entity type, if needed.
*
- * @dataProvider basicModerationTestCases
+ * @param string $entity_type_id
+ * The entity type identifier.
+ *
+ * @return string
+ * The bundle identifier.
*/
- public function testBasicModeration($entity_type_id) {
+ protected function setupBundleEntityType($entity_type_id) {
// Make the 'entity_test_with_bundle' entity type revisionable.
if ($entity_type_id == 'entity_test_with_bundle') {
$this->setEntityTestWithBundleKeys(['revision' => 'revision_id']);
}
- $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
$bundle_id = $entity_type_id;
$bundle_entity_type_id = $this->entityTypeManager->getDefinition($entity_type_id)->getBundleEntityType();
if ($bundle_entity_type_id) {
@@ -112,6 +116,19 @@ class ContentModerationStateTest extends KernelTestBase {
$workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
$workflow->save();
+ return $bundle_id;
+ }
+
+ /**
+ * Tests basic monolingual content moderation through the API.
+ *
+ * @dataProvider basicModerationTestCases
+ */
+ public function testBasicModeration($entity_type_id) {
+ $bundle_id = $this->setupBundleEntityType($entity_type_id);
+
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
$entity = $entity_storage->create([
'title' => 'Test title',
$this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
@@ -214,6 +231,69 @@ class ContentModerationStateTest extends KernelTestBase {
}
/**
+ * Tests removal of content moderation state entity field data.
+ *
+ * @dataProvider basicModerationTestCases
+ */
+ public function testContentModerationStateDataRemoval($entity_type_id) {
+ $bundle_id = $this->setupBundleEntityType($entity_type_id);
+
+ // Test content moderation state deletion.
+ $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+ $entity = $entity_storage->create([
+ 'title' => 'Test title',
+ $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
+ ]);
+ $entity->save();
+ $entity = $this->reloadEntity($entity);
+ $entity->delete();
+ $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity);
+ $this->assertFalse($content_moderation_state);
+
+ // Test content moderation state revision deletion.
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity2 */
+ $entity2 = $entity_storage->create([
+ 'title' => 'Test title',
+ $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
+ ]);
+ $entity2->save();
+ $revision = clone $entity2;
+ $revision->isDefaultRevision(FALSE);
+ $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
+ $this->assertTrue($content_moderation_state);
+ $entity2 = $this->reloadEntity($entity2);
+ $entity2->setNewRevision(TRUE);
+ $entity2->save();
+ $entity_storage->deleteRevision($revision->getRevisionId());
+ $content_moderation_state = ContentModerationState::loadFromModeratedEntity($revision);
+ $this->assertFalse($content_moderation_state);
+ $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity2);
+ $this->assertTrue($content_moderation_state);
+
+ // Test content moderation state translation deletion.
+ if ($this->entityTypeManager->getDefinition($entity_type_id)->isTranslatable()) {
+ /** @var \Drupal\Core\Entity\ContentEntityInterface $entity3 */
+ $entity3 = $entity_storage->create([
+ 'title' => 'Test title',
+ $this->entityTypeManager->getDefinition($entity_type_id)->getKey('bundle') => $bundle_id,
+ ]);
+ $langcode = 'it';
+ ConfigurableLanguage::createFromLangcode($langcode)
+ ->save();
+ $entity3->save();
+ $translation = $entity3->addTranslation($langcode, ['title' => 'Titolo test']);
+ $translation->save();
+ $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity3);
+ $this->assertTrue($content_moderation_state->hasTranslation($langcode));
+ $entity3->removeTranslation($langcode);
+ $entity3->save();
+ $content_moderation_state = ContentModerationState::loadFromModeratedEntity($entity3);
+ $this->assertFalse($content_moderation_state->hasTranslation($langcode));
+ }
+ }
+
+ /**
* Tests basic multilingual content moderation through the API.
*/
public function testMultilingualModeration() {