Commit e6f77992 authored by catch's avatar catch

Issue #2893888 by plach, Sam152, amateescu, evilehk: Content moderation state...

Issue #2893888 by plach, Sam152, amateescu, evilehk: Content moderation state entity field data not removed when the host field data is
parent bff6783e
......@@ -91,6 +91,33 @@ function content_moderation_entity_update(EntityInterface $entity) {
->entityUpdate($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().
*/
......
......@@ -4,6 +4,7 @@
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;
......@@ -142,6 +143,44 @@ public static function updateOrCreateFromEntity(ContentModerationState $content_
$content_moderation_state->realSave();
}
/**
* 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.
*
......
......@@ -154,31 +154,16 @@ public function entityUpdate(EntityInterface $entity) {
* 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 @@ protected function updateOrCreateFromEntity(EntityInterface $entity) {
}
// 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);
......@@ -224,6 +216,61 @@ protected function setLatestRevision(EntityInterface $entity) {
);
}
/**
* 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.
*
......
......@@ -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 @@ protected function setUp() {
}
/**
* 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 @@ public function testBasicModeration($entity_type_id) {
$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,
......@@ -213,6 +230,69 @@ public function basicModerationTestCases() {
];
}
/**
* 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.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment