Commit ba726bed authored by catch's avatar catch

Issue #2915383 by Sam152, amateescu, jibran: The moderation_state base field...

Issue #2915383 by Sam152, amateescu, jibran: The moderation_state base field is added to all revisionable entity types even if they do not have moderation enabled
parent 3ba6bc11
......@@ -21,6 +21,9 @@
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\views\Plugin\views\filter\Broken;
use Drupal\views\ViewExecutable;
use Drupal\views\Views;
use Drupal\workflows\WorkflowInterface;
use Drupal\Core\Action\Plugin\Action\PublishAction;
use Drupal\Core\Action\Plugin\Action\UnpublishAction;
......@@ -64,6 +67,20 @@ function content_moderation_entity_base_field_info(EntityTypeInterface $entity_t
->entityBaseFieldInfo($entity_type);
}
/**
* Implements hook_entity_bundle_field_info().
*/
function content_moderation_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
if (isset($base_field_definitions['moderation_state'])) {
// Add the target bundle to the moderation state field. Since each bundle
// can be attached to a different moderation workflow, adding this
// information to the field definition allows the associated workflow to be
// derived where a field definition is present.
$base_field_definitions['moderation_state']->setTargetBundle($bundle);
return $base_field_definitions;
}
}
/**
* Implements hook_entity_type_alter().
*/
......@@ -316,6 +333,10 @@ function content_moderation_workflow_insert(WorkflowInterface $entity) {
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
// Clear field cache so extra field is added or removed.
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
// Clear the views data cache so the extra field is available in views.
if (\Drupal::moduleHandler()->moduleExists('views')) {
Views::viewsData()->clear();
}
}
/**
......@@ -327,4 +348,22 @@ function content_moderation_workflow_update(WorkflowInterface $entity) {
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
// Clear field cache so extra field is added or removed.
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
// Clear the views data cache so the extra field is available in views.
if (\Drupal::moduleHandler()->moduleExists('views')) {
Views::viewsData()->clear();
}
}
/**
* Implements hook_views_post_execute().
*/
function content_moderation_views_post_execute(ViewExecutable $view) {
// @todo, remove this once broken handlers in views configuration result in
// a view no longer returning results. https://www.drupal.org/node/2907954.
foreach ($view->filter as $id => $filter) {
if (strpos($id, 'moderation_state') === 0 && $filter instanceof Broken) {
$view->result = [];
break;
}
}
}
......@@ -6,6 +6,7 @@
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Site\Settings;
use Drupal\views\Entity\View;
use Drupal\workflows\Entity\Workflow;
......@@ -138,3 +139,34 @@ function content_moderation_post_update_set_views_filter_latest_translation_affe
$view->save();
}
}
/**
* Update the dependencies of entity displays to include associated workflow.
*/
function content_moderation_post_update_entity_display_dependencies(&$sandbox) {
/** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
$moderation_info = \Drupal::service('content_moderation.moderation_information');
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
$entity_type_manager = \Drupal::service('entity_type.manager');
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_form_display', function (EntityFormDisplay $entity_form_display) use ($moderation_info, $entity_type_manager) {
$associated_entity_type = $entity_type_manager->getDefinition($entity_form_display->getTargetEntityTypeId());
if ($moderation_info->isModeratedEntityType($associated_entity_type)) {
$entity_form_display->calculateDependencies();
return TRUE;
}
elseif ($moderation_state_component = $entity_form_display->getComponent('moderation_state')) {
// Remove the component from the entity form display, then manually delete
// it from the hidden components list, completely purging it.
$entity_form_display->removeComponent('moderation_state');
$hidden_components = $entity_form_display->get('hidden');
unset($hidden_components['moderation_state']);
$entity_form_display->set('hidden', $hidden_components);
$entity_form_display->calculateDependencies();
return TRUE;
}
return FALSE;
});
}
......@@ -240,7 +240,7 @@ protected function getModeratedBundles() {
* @see hook_entity_base_field_info()
*/
public function entityBaseFieldInfo(EntityTypeInterface $entity_type) {
if (!$this->moderationInfo->canModerateEntitiesOfEntityType($entity_type)) {
if (!$this->moderationInfo->isModeratedEntityType($entity_type)) {
return [];
}
......
......@@ -56,6 +56,14 @@ public function isModeratedEntity(EntityInterface $entity) {
return $this->shouldModerateEntitiesOfBundle($entity->getEntityType(), $entity->bundle());
}
/**
* {@inheritdoc}
*/
public function isModeratedEntityType(EntityTypeInterface $entity_type) {
$bundles = $this->bundleInfo->getBundleInfo($entity_type->id());
return !empty(array_column($bundles, 'workflow'));
}
/**
* {@inheritdoc}
*/
......@@ -206,10 +214,17 @@ public function isDefaultRevisionPublished(ContentEntityInterface $entity) {
* {@inheritdoc}
*/
public function getWorkflowForEntity(ContentEntityInterface $entity) {
$bundles = $this->bundleInfo->getBundleInfo($entity->getEntityTypeId());
if (isset($bundles[$entity->bundle()]['workflow'])) {
return $this->entityTypeManager->getStorage('workflow')->load($bundles[$entity->bundle()]['workflow']);
};
return $this->getWorkflowForEntityTypeAndBundle($entity->getEntityTypeId(), $entity->bundle());
}
/**
* {@inheritdoc}
*/
public function getWorkflowForEntityTypeAndBundle($entity_type_id, $bundle_id) {
$bundles = $this->bundleInfo->getBundleInfo($entity_type_id);
if (isset($bundles[$bundle_id]['workflow'])) {
return $this->entityTypeManager->getStorage('workflow')->load($bundles[$bundle_id]['workflow']);
}
return NULL;
}
......
......@@ -47,6 +47,17 @@ public function canModerateEntitiesOfEntityType(EntityTypeInterface $entity_type
*/
public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type, $bundle);
/**
* Determines if an entity type has at least one moderated bundle.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type definition to check.
*
* @return bool
* TRUE if an entity type has a moderated bundle, FALSE otherwise.
*/
public function isModeratedEntityType(EntityTypeInterface $entity_type);
/**
* Loads the latest revision of a specific entity.
*
......@@ -163,6 +174,19 @@ public function isDefaultRevisionPublished(ContentEntityInterface $entity);
*/
public function getWorkflowForEntity(ContentEntityInterface $entity);
/**
* Gets the workflow for the given entity type and bundle.
*
* @param string $entity_type_id
* The entity type ID.
* @param string $bundle_id
* The entity bundle ID.
*
* @return \Drupal\workflows\WorkflowInterface|null
* The associated workflow. NULL if there is no workflow.
*/
public function getWorkflowForEntityTypeAndBundle($entity_type_id, $bundle_id);
/**
* Gets unsupported features for a given entity type.
*
......
......@@ -178,4 +178,15 @@ public static function isApplicable(FieldDefinitionInterface $field_definition)
return is_a($field_definition->getClass(), ModerationStateFieldItemList::class, TRUE);
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
if ($workflow = $this->moderationInformation->getWorkflowForEntityTypeAndBundle($this->fieldDefinition->getTargetEntityTypeId(), $this->fieldDefinition->getTargetBundle())) {
$dependencies[$workflow->getConfigDependencyKey()][] = $workflow->getConfigDependencyName();
}
return $dependencies;
}
}
......@@ -52,7 +52,7 @@ public function getViewsData() {
$data = [];
$entity_types_with_moderation = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $type) {
return $this->moderationInformation->canModerateEntitiesOfEntityType($type);
return $this->moderationInformation->isModeratedEntityType($type);
});
// Provides a relationship from moderated entity to its moderation state
......
<?php
// @codingStandardsIgnoreFile
/**
* @file
* Content for the update path test in #2915383.
*
* @see \Drupal\Tests\content_moderation\Functional\EntityFormDisplayDependenciesUpdateTest
*/
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
$connection->update('config')
->fields([
'data' => 'a:11:{s:4:"uuid";s:36:"16624d7d-0800-4ed7-9861-41f7e71394a8";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:2:{s:6:"config";a:2:{i:0;s:24:"block_content.type.basic";i:1;s:36:"field.field.block_content.basic.body";}s:6:"module";a:2:{i:0;s:18:"content_moderation";i:1;s:4:"text";}}s:5:"_core";a:1:{s:19:"default_config_hash";s:43:"e1Nu5xXAuF_QplbBUhQBPLnYWvHtDX0MkZnpuCiY8uM";}s:2:"id";s:27:"block_content.basic.default";s:16:"targetEntityType";s:13:"block_content";s:6:"bundle";s:5:"basic";s:4:"mode";s:7:"default";s:7:"content";a:3:{s:4:"body";a:5:{s:4:"type";s:26:"text_textarea_with_summary";s:6:"weight";i:-4;s:6:"region";s:7:"content";s:8:"settings";a:3:{s:4:"rows";i:9;s:12:"summary_rows";i:3;s:11:"placeholder";s:0:"";}s:20:"third_party_settings";a:0:{}}s:4:"info";a:5:{s:4:"type";s:16:"string_textfield";s:6:"weight";i:-5;s:6:"region";s:7:"content";s:8:"settings";a:2:{s:4:"size";i:60;s:11:"placeholder";s:0:"";}s:20:"third_party_settings";a:0:{}}s:16:"moderation_state";a:5:{s:4:"type";s:24:"moderation_state_default";s:6:"weight";i:100;s:8:"settings";a:0:{}s:6:"region";s:7:"content";s:20:"third_party_settings";a:0:{}}}s:6:"hidden";a:0:{}}',
])
->condition('name', 'core.entity_form_display.block_content.basic.default')
->execute();
$connection->update('config')
->fields([
'data' => 'a:11:{s:4:"uuid";s:36:"af6ca931-0ecc-46c0-8097-ffb383db6287";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:2:{s:6:"config";a:6:{i:0;s:29:"field.field.node.article.body";i:1;s:32:"field.field.node.article.comment";i:2;s:36:"field.field.node.article.field_image";i:3;s:35:"field.field.node.article.field_tags";i:4;s:21:"image.style.thumbnail";i:5;s:17:"node.type.article";}s:6:"module";a:5:{i:0;s:7:"comment";i:1;s:18:"content_moderation";i:2;s:5:"image";i:3;s:4:"path";i:4;s:4:"text";}}s:5:"_core";a:1:{s:19:"default_config_hash";s:43:"buc38w3gxCqFnjINJhMiJvPpj9jWflKvlKDyBVMPVvw";}s:2:"id";s:20:"node.article.default";s:16:"targetEntityType";s:4:"node";s:6:"bundle";s:7:"article";s:4:"mode";s:7:"default";s:7:"content";a:12:{s:4:"body";a:5:{s:4:"type";s:26:"text_textarea_with_summary";s:6:"weight";i:1;s:6:"region";s:7:"content";s:8:"settings";a:3:{s:4:"rows";i:9;s:12:"summary_rows";i:3;s:11:"placeholder";s:0:"";}s:20:"third_party_settings";a:0:{}}s:7:"comment";a:5:{s:4:"type";s:15:"comment_default";s:6:"weight";i:20;s:6:"region";s:7:"content";s:8:"settings";a:0:{}s:20:"third_party_settings";a:0:{}}s:7:"created";a:5:{s:4:"type";s:18:"datetime_timestamp";s:6:"weight";i:10;s:6:"region";s:7:"content";s:8:"settings";a:0:{}s:20:"third_party_settings";a:0:{}}s:11:"field_image";a:5:{s:4:"type";s:11:"image_image";s:6:"weight";i:4;s:6:"region";s:7:"content";s:8:"settings";a:2:{s:18:"progress_indicator";s:8:"throbber";s:19:"preview_image_style";s:9:"thumbnail";}s:20:"third_party_settings";a:0:{}}s:10:"field_tags";a:5:{s:4:"type";s:34:"entity_reference_autocomplete_tags";s:6:"weight";i:3;s:6:"region";s:7:"content";s:8:"settings";a:3:{s:14:"match_operator";s:8:"CONTAINS";s:4:"size";i:60;s:11:"placeholder";s:0:"";}s:20:"third_party_settings";a:0:{}}s:16:"moderation_state";a:5:{s:4:"type";s:24:"moderation_state_default";s:6:"weight";i:100;s:8:"settings";a:0:{}s:6:"region";s:7:"content";s:20:"third_party_settings";a:0:{}}s:4:"path";a:5:{s:4:"type";s:4:"path";s:6:"weight";i:30;s:6:"region";s:7:"content";s:8:"settings";a:0:{}s:20:"third_party_settings";a:0:{}}s:7:"promote";a:5:{s:4:"type";s:16:"boolean_checkbox";s:8:"settings";a:1:{s:13:"display_label";b:1;}s:6:"weight";i:15;s:6:"region";s:7:"content";s:20:"third_party_settings";a:0:{}}s:6:"status";a:5:{s:4:"type";s:16:"boolean_checkbox";s:8:"settings";a:1:{s:13:"display_label";b:1;}s:6:"weight";i:120;s:6:"region";s:7:"content";s:20:"third_party_settings";a:0:{}}s:6:"sticky";a:5:{s:4:"type";s:16:"boolean_checkbox";s:8:"settings";a:1:{s:13:"display_label";b:1;}s:6:"weight";i:16;s:6:"region";s:7:"content";s:20:"third_party_settings";a:0:{}}s:5:"title";a:5:{s:4:"type";s:16:"string_textfield";s:6:"weight";i:0;s:6:"region";s:7:"content";s:8:"settings";a:2:{s:4:"size";i:60;s:11:"placeholder";s:0:"";}s:20:"third_party_settings";a:0:{}}s:3:"uid";a:5:{s:4:"type";s:29:"entity_reference_autocomplete";s:6:"weight";i:5;s:6:"region";s:7:"content";s:8:"settings";a:3:{s:14:"match_operator";s:8:"CONTAINS";s:4:"size";i:60;s:11:"placeholder";s:0:"";}s:20:"third_party_settings";a:0:{}}}s:6:"hidden";a:0:{}}',
])
->condition('name', 'core.entity_form_display.node.article.default')
->execute();
$connection->update('config')
->fields([
'data' => 'a:9:{s:4:"uuid";s:36:"08b548c7-ff59-468b-9347-7d697680d035";s:8:"langcode";s:2:"en";s:6:"status";b:1;s:12:"dependencies";a:2:{s:6:"config";a:2:{i:0;s:17:"node.type.article";i:1;s:14:"node.type.page";}s:6:"module";a:1:{i:0;s:18:"content_moderation";}}s:5:"_core";a:1:{s:19:"default_config_hash";s:43:"T_JxNjYlfoRBi7Bj1zs5Xv9xv1btuBkKp5C1tNrjMhI";}s:2:"id";s:9:"editorial";s:5:"label";s:9:"Editorial";s:4:"type";s:18:"content_moderation";s:13:"type_settings";a:3:{s:6:"states";a:3:{s:8:"archived";a:4:{s:5:"label";s:8:"Archived";s:6:"weight";i:5;s:9:"published";b:0;s:16:"default_revision";b:1;}s:5:"draft";a:4:{s:5:"label";s:5:"Draft";s:9:"published";b:0;s:16:"default_revision";b:0;s:6:"weight";i:-5;}s:9:"published";a:4:{s:5:"label";s:9:"Published";s:9:"published";b:1;s:16:"default_revision";b:1;s:6:"weight";i:0;}}s:11:"transitions";a:5:{s:7:"archive";a:4:{s:5:"label";s:7:"Archive";s:4:"from";a:1:{i:0;s:9:"published";}s:2:"to";s:8:"archived";s:6:"weight";i:2;}s:14:"archived_draft";a:4:{s:5:"label";s:16:"Restore to Draft";s:4:"from";a:1:{i:0;s:8:"archived";}s:2:"to";s:5:"draft";s:6:"weight";i:3;}s:18:"archived_published";a:4:{s:5:"label";s:7:"Restore";s:4:"from";a:1:{i:0;s:8:"archived";}s:2:"to";s:9:"published";s:6:"weight";i:4;}s:16:"create_new_draft";a:4:{s:5:"label";s:16:"Create New Draft";s:2:"to";s:5:"draft";s:6:"weight";i:0;s:4:"from";a:2:{i:0;s:5:"draft";i:1;s:9:"published";}}s:7:"publish";a:4:{s:5:"label";s:7:"Publish";s:2:"to";s:9:"published";s:6:"weight";i:1;s:4:"from";a:2:{i:0;s:5:"draft";i:1;s:9:"published";}}}s:12:"entity_types";a:1:{s:4:"node";a:2:{i:0;s:7:"article";i:1;s:4:"page";}}}}',
])
->condition('name', 'workflows.workflow.editorial')
->execute();
<?php
namespace Drupal\Tests\content_moderation\Functional;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Test updating the dependencies of entity form displays.
*
* @group Update
* @group legacy
*
* @see content_moderation_post_update_entity_display_dependencies()
*/
class EntityFormDisplayDependenciesUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
__DIR__ . '/../../fixtures/update/drupal-8.4.0-content_moderation_installed.php',
__DIR__ . '/../../fixtures/update/drupal-8.entity-form-display-dependencies-2915383.php',
];
}
/**
* Tests updating the dependencies of entity displays.
*/
public function testEntityDisplaysUpdated() {
$no_moderation_form_display = EntityFormDisplay::load('block_content.basic.default');
$has_moderation_form_display = EntityFormDisplay::load('node.article.default');
// Assert the moderation field and content_moderation dependency exists on
// an entity type that does not have moderation enabled, these will be
// removed.
$this->assertEquals('moderation_state_default', $no_moderation_form_display->getComponent('moderation_state')['type']);
$this->assertTrue(in_array('content_moderation', $no_moderation_form_display->getDependencies()['module']));
// Assert the editorial config dependency doesn't exist on the entity form
// with moderation, this will be added.
$this->assertFalse(in_array('workflows.workflow.editorial', $has_moderation_form_display->getDependencies()['config']));
$this->runUpdates();
$no_moderation_form_display = EntityFormDisplay::load('block_content.basic.default');
$has_moderation_form_display = EntityFormDisplay::load('node.article.default');
// The moderation_state field has been removed from the non-moderated block
// entity form display.
$this->assertEquals(NULL, $no_moderation_form_display->getComponent('moderation_state'));
$this->assertFalse(in_array('content_moderation', $no_moderation_form_display->getDependencies()['module']));
// The editorial workflow config dependency has been added to moderated
// form display.
$this->assertTrue(in_array('workflows.workflow.editorial', $has_moderation_form_display->getDependencies()['config']));
}
}
......@@ -20,17 +20,33 @@ class ModerationStateAccessTest extends BrowserTestBase {
* {@inheritdoc}
*/
public static $modules = [
'content_moderation_test_views',
'content_moderation',
'node',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$node_type = NodeType::create([
'type' => 'test',
'label' => 'Test',
]);
$node_type->save();
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'test');
$workflow->save();
$this->container->get('module_installer')->install(['content_moderation_test_views']);
}
/**
* Test the view operation access handler with the view permission.
*/
public function testViewShowsCorrectStates() {
$node_type_id = 'test';
$this->createNodeType('Test', $node_type_id);
$permissions = [
'access content',
'view all revisions',
......@@ -39,7 +55,7 @@ public function testViewShowsCorrectStates() {
$this->drupalLogin($editor1);
$node_1 = Node::create([
'type' => $node_type_id,
'type' => 'test',
'title' => 'Draft node',
'uid' => $editor1->id(),
]);
......@@ -47,7 +63,7 @@ public function testViewShowsCorrectStates() {
$node_1->save();
$node_2 = Node::create([
'type' => $node_type_id,
'type' => 'test',
'title' => 'Published node',
'uid' => $editor1->id(),
]);
......@@ -82,29 +98,4 @@ public function testViewShowsCorrectStates() {
$this->assertFalse($page->hasContent('Published'));
}
/**
* Creates a new node type.
*
* @param string $label
* The human-readable label of the type to create.
* @param string $machine_name
* The machine name of the type to create.
*
* @return \Drupal\node\Entity\NodeType
* The node type just created.
*/
protected function createNodeType($label, $machine_name) {
/** @var \Drupal\node\Entity\NodeType $node_type */
$node_type = NodeType::create([
'type' => $machine_name,
'label' => $label,
]);
$node_type->save();
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', $machine_name);
$workflow->save();
return $node_type;
}
}
......@@ -71,7 +71,7 @@ public function testCreatingContent() {
if (!$node) {
$this->fail('Non-moderated test node was not saved correctly.');
}
$this->assertEqual(NULL, $node->moderation_state->value);
$this->assertFalse($node->hasField('moderation_state'));
}
/**
......
......@@ -161,6 +161,7 @@ public function testInvalidStateWithoutExisting() {
$workflow->save();
// Validate the invalid state.
$node = Node::load($node->id());
$node->moderation_state->value = 'invalid_state';
$violations = $node->validate();
$this->assertCount(1, $violations);
......
......@@ -4,7 +4,9 @@
use Drupal\content_moderation\Entity\Handler\ModerationHandler;
use Drupal\content_moderation\EntityTypeInfo;
use Drupal\entity_test\Entity\EntityTestBundle;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
/**
* @coversDefaultClass \Drupal\content_moderation\EntityTypeInfo
......@@ -13,6 +15,8 @@
*/
class EntityTypeInfoTest extends KernelTestBase {
use ContentModerationTestTrait;
/**
* Modules to enable.
*
......@@ -43,8 +47,11 @@ class EntityTypeInfoTest extends KernelTestBase {
*/
protected function setUp() {
parent::setUp();
$this->entityTypeInfo = $this->container->get('class_resolver')->getInstanceFromDefinition(EntityTypeInfo::class);
$this->entityTypeManager = $this->container->get('entity_type.manager');
$this->installConfig(['content_moderation']);
}
/**
......@@ -54,6 +61,7 @@ public function testEntityBaseFieldInfo() {
$definition = $this->entityTypeManager->getDefinition('entity_test');
$definition->setHandlerClass('moderation', ModerationHandler::class);
$this->enableModeration('entity_test', 'entity_test');
$base_fields = $this->entityTypeInfo->entityBaseFieldInfo($definition);
$this->assertFalse($base_fields['moderation_state']->isReadOnly());
......@@ -91,4 +99,34 @@ public function providerTestEntityTypeAlter() {
return $tests;
}
/**
* @covers ::entityBaseFieldInfo
*/
public function testBaseFieldOnlyAddedToModeratedEntityTypes() {
$definition = $this->entityTypeManager->getDefinition('entity_test_with_bundle');
EntityTestBundle::create([
'id' => 'moderated',
])->save();
EntityTestBundle::create([
'id' => 'unmoderated',
])->save();
$base_fields = $this->entityTypeInfo->entityBaseFieldInfo($definition);
$this->assertFalse(isset($base_fields['moderation_state']));
$this->enableModeration('entity_test_with_bundle', 'moderated');
$base_fields = $this->entityTypeInfo->entityBaseFieldInfo($definition);
$this->assertTrue(isset($base_fields['moderation_state']));
}
/**
* Add moderation to an entity type and bundle.
*/
protected function enableModeration($entity_type_id, $bundle) {
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle);
$workflow->save();
}
}
......@@ -39,7 +39,6 @@ protected function setUp($import_test_views = TRUE) {
$this->installEntitySchema('user');
$this->installEntitySchema('content_moderation_state');
$this->installSchema('node', 'node_access');
$this->installConfig('content_moderation_test_views');
$this->installConfig('content_moderation');
$node_type = NodeType::create([
......@@ -50,6 +49,8 @@ protected function setUp($import_test_views = TRUE) {
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_mulrevpub', 'entity_test_mulrevpub');
$workflow->save();
$this->installConfig('content_moderation_test_views');
}
/**
......
......@@ -47,7 +47,6 @@ protected function setUp($import_test_views = TRUE) {
$this->installEntitySchema('content_moderation_state');
$this->installEntitySchema('entity_test_no_bundle');
$this->installSchema('node', 'node_access');
$this->installConfig('content_moderation_test_views');
$this->installConfig('content_moderation');
$node_type = NodeType::create([
......@@ -65,6 +64,14 @@ protected function setUp($import_test_views = TRUE) {
]);
$node_type->save();
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
$workflow->save();
// Install the test views after moderation has been enabled on the example
// bundle, so the moderation_state field exists.
$this->installConfig('content_moderation_test_views');
ConfigurableLanguage::createFromLangcode('fr')->save();
}
......@@ -72,7 +79,7 @@ protected function setUp($import_test_views = TRUE) {
* Tests the content moderation state filter.
*/
public function testStateFilterViewsRelationship() {
$workflow = $this->createEditorialWorkflow();
$workflow = Workflow::load('editorial');
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
$workflow->getTypePlugin()->addState('translated_draft', 'Bar');
$configuration = $workflow->getTypePlugin()->getConfiguration();
......@@ -159,7 +166,7 @@ public function testStateFilterViewsRelationship() {
* Test the moderation filter with a non-translatable entity type.
*/
public function testNonTranslatableEntityType() {
$workflow = $this->createEditorialWorkflow();
$workflow = Workflow::load('editorial');
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_no_bundle', 'entity_test_no_bundle');
$workflow->save();
......@@ -181,11 +188,13 @@ public function testNonTranslatableEntityType() {
*/
public function testStateFilterStatesList() {
// By default a view of nodes will not have states to filter.
$workflow = Workflow::load('editorial');
$workflow->getTypePlugin()->removeEntityTypeAndBundle('node', 'example');
$workflow->save();
$this->assertPluginStates([]);
// Adding a content type to the editorial workflow will enable all of the
// editorial states.
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
$workflow->save();
$this->assertPluginStates([
......
......@@ -7,6 +7,7 @@
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\content_moderation\ModerationInformation;
......@@ -58,10 +59,27 @@ public function setupModerationBundleInfo($bundle, $workflow = NULL) {
}
$bundle_info = $this->prophesize(EntityTypeBundleInfoInterface::class);
$bundle_info->getBundleInfo("test_entity_type")->willReturn([$bundle => $bundle_info_array]);
$bundle_info->getBundleInfo("unmoderated_test_type")->willReturn([$bundle => []]);
return $bundle_info->reveal();
}
/**
* @covers ::isModeratedEntityType
*/
public function testIsModeratedEntityType() {
$moderation_information = new ModerationInformation($this->getEntityTypeManager(), $this->setupModerationBundleInfo('test_bundle', 'workflow'));
$moderated_entity_type = $this->prophesize(EntityTypeInterface::class);
$moderated_entity_type->id()->willReturn('test_entity_type');
$unmoderated_entity_type = $this->prophesize(EntityTypeInterface::class);
$unmoderated_entity_type->id()->willReturn('unmoderated_test_type');
$this->assertTrue($moderation_information->isModeratedEntityType($moderated_entity_type->reveal()));
$this->assertFalse($moderation_information->isModeratedEntityType($unmoderated_entity_type->reveal()));
}
/**
* @dataProvider providerWorkflow
* @covers ::isModeratedEntity
......
......@@ -7,6 +7,7 @@ dependencies:
- field.field.node.article.field_tags
- image.style.thumbnail
- node.type.article
- workflows.workflow.editorial
module:
- content_moderation
- image
......
......@@ -4,6 +4,7 @@ dependencies:
config:
- field.field.node.page.body
- node.type.page
- workflows.workflow.editorial
module:
- content_moderation
- path
......
......@@ -14,6 +14,7 @@ dependencies:
- field.field.node.recipe.field_tags
- image.style.thumbnail
- node.type.recipe
- workflows.workflow.editorial
module:
- content_moderation
- image
......
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