Issue #2830581 by alexpott, Sam152, timmillwood, xjm: Fix ContentModeration workflow type to calculate correct dependencies

8.4.x
xjm 2017-02-10 15:00:17 -06:00
parent 22d62194b3
commit 758f01b6f6
9 changed files with 218 additions and 7 deletions

View File

@ -3,13 +3,16 @@
namespace Drupal\content_moderation\Plugin\WorkflowType;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\content_moderation\ContentModerationState;
use Drupal\workflows\Plugin\WorkflowTypeBase;
use Drupal\workflows\StateInterface;
use Drupal\workflows\WorkflowInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Attaches workflows to content entity types and their bundles.
@ -23,10 +26,37 @@ use Drupal\workflows\WorkflowInterface;
* },
* )
*/
class ContentModeration extends WorkflowTypeBase {
class ContentModeration extends WorkflowTypeBase implements ContainerFactoryPluginInterface {
use StringTranslationTrait;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Creates an instance of the ContentModeration WorkflowType plugin.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
@ -193,11 +223,59 @@ class ContentModeration extends WorkflowTypeBase {
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function calculateDependencies() {
// @todo : Implement calculateDependencies() method.
return [];
$dependencies = parent::calculateDependencies();
foreach ($this->getEntityTypes() as $entity_type_id) {
$entity_definition = $this->entityTypeManager->getDefinition($entity_type_id);
foreach ($this->getBundlesForEntityType($entity_type_id) as $bundle) {
$dependency = $entity_definition->getBundleConfigDependency($bundle);
$dependencies[$dependency['type']][] = $dependency['name'];
}
}
return $dependencies;
}
/**
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
$changed = parent::onDependencyRemoval($dependencies);
// When bundle config entities are removed, ensure they are cleaned up from
// the workflow.
foreach ($dependencies['config'] as $removed_config) {
if ($entity_type_id = $removed_config->getEntityType()->getBundleOf()) {
$bundle_id = $removed_config->id();
$this->removeEntityTypeAndBundle($entity_type_id, $bundle_id);
$changed = TRUE;
}
}
// When modules that provide entity types are removed, ensure they are also
// removed from the workflow.
if (!empty($dependencies['module'])) {
// Gather all entity definitions provided by the dependent modules which
// are being removed.
$module_entity_definitions = [];
foreach ($this->entityTypeManager->getDefinitions() as $entity_definition) {
if (in_array($entity_definition->getProvider(), $dependencies['module'])) {
$module_entity_definitions[] = $entity_definition;
}
}
// For all entity types provided by the uninstalled modules, remove any
// configuration for those types.
foreach ($module_entity_definitions as $module_entity_definition) {
foreach ($this->getBundlesForEntityType($module_entity_definition->id()) as $bundle) {
$this->removeEntityTypeAndBundle($module_entity_definition->id(), $bundle);
$changed = TRUE;
}
}
}
return $changed;
}
/**

View File

@ -387,6 +387,48 @@ class ContentModerationStateTest extends KernelTestBase {
\Drupal::entityDefinitionUpdateManager()->applyUpdates();
}
/**
* Tests the dependencies of the workflow when using content moderation.
*/
public function testWorkflowDependencies() {
$node_type = NodeType::create([
'type' => 'example',
]);
$node_type->save();
$workflow = Workflow::load('editorial');
// Test both a config and non-config based bundle and entity type.
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'example');
$workflow->getTypePlugin()->addEntityTypeAndBundle('entity_test_rev', 'entity_test_rev');
$workflow->save();
$this->assertEquals([
'module' => [
'content_moderation',
'entity_test',
],
'config' => [
'node.type.example',
],
], $workflow->getDependencies());
$entity_types = $workflow->getTypePlugin()->getEntityTypes();
$this->assertTrue(in_array('node', $entity_types));
$this->assertTrue(in_array('entity_test_rev', $entity_types));
// Delete the node type and ensure it is removed from the workflow.
$node_type->delete();
$workflow = Workflow::load('editorial');
$entity_types = $workflow->getTypePlugin()->getEntityTypes();
$this->assertFalse(in_array('node', $entity_types));
// Uninstall entity test and ensure it's removed from the workflow.
$this->container->get('config.manager')->uninstall('module', 'entity_test');
$workflow = Workflow::load('editorial');
$entity_types = $workflow->getTypePlugin()->getEntityTypes();
$this->assertFalse(in_array('entity_test_rev', $entity_types));
}
/**
* Reloads the entity after clearing the static cache.
*

View File

@ -520,4 +520,14 @@ class Workflow extends ConfigEntityBase implements WorkflowInterface, EntityWith
return !empty($this->status) && !empty($this->states);
}
/**
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
$changed = $this->getTypePlugin()->onDependencyRemoval($dependencies);
// Ensure the parent method is called in order to process dependencies that
// affect third party settings.
return parent::onDependencyRemoval($dependencies) || $changed;
}
}

View File

@ -138,4 +138,11 @@ abstract class WorkflowTypeBase extends PluginBase implements WorkflowTypeInterf
return [];
}
/**
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
return FALSE;
}
}

View File

@ -25,7 +25,7 @@ interface WorkflowTypeInterface extends PluginInspectionInterface, DerivativeIns
* @param \Drupal\workflows\WorkflowInterface $workflow
* The workflow to initialize.
*
* @return \Drupal\workflows\WorkflowInterface $workflow
* @return \Drupal\workflows\WorkflowInterface
* The initialized workflow.
*
* @see \Drupal\workflows\Form\WorkflowAddForm::save()
@ -62,7 +62,7 @@ interface WorkflowTypeInterface extends PluginInspectionInterface, DerivativeIns
* @param \Drupal\workflows\StateInterface $state
* The state object to decorate.
*
* @return \Drupal\workflows\StateInterface $state
* @return \Drupal\workflows\StateInterface
* The decorated state object.
*/
public function decorateState(StateInterface $state);
@ -80,7 +80,7 @@ interface WorkflowTypeInterface extends PluginInspectionInterface, DerivativeIns
* @param \Drupal\workflows\TransitionInterface $transition
* The transition object to decorate.
*
* @return \Drupal\workflows\TransitionInterface $transition
* @return \Drupal\workflows\TransitionInterface
* The decorated transition object.
*/
public function decorateTransition(TransitionInterface $transition);
@ -144,4 +144,19 @@ interface WorkflowTypeInterface extends PluginInspectionInterface, DerivativeIns
*/
public function getRequiredStates();
/**
* Informs the plugin that a dependency of the workflow will be deleted.
*
* @param array $dependencies
* An array of dependencies that will be deleted keyed by dependency type.
*
* @return bool
* TRUE if the workflow settings have been changed, FALSE if not.
*
* @see \Drupal\Core\Config\ConfigEntityInterface::onDependencyRemoval()
*
* @todo https://www.drupal.org/node/2579743 make part of a generic interface.
*/
public function onDependencyRemoval(array $dependencies);
}

View File

@ -0,0 +1,2 @@
workflows.workflow.*.third_party.workflow_third_party_settings_test:
type: ignore

View File

@ -0,0 +1,8 @@
name: 'Workflow Third Party Settings Test'
type: module
description: 'Allows third party settings on workflows to be tested.'
package: Testing
version: VERSION
core: 8.x
dependencies:
- workflows

View File

@ -79,4 +79,13 @@ class ComplexTestType extends WorkflowTypeBase {
return $form;
}
/**
* {@inheritdoc}
*/
public function onDependencyRemoval(array $dependencies) {
// Always return TRUE to allow the logic in
// \Drupal\workflows\Entity\Workflow::onDependencyRemoval() to be tested.
return TRUE;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Drupal\Tests\workflows\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\workflows\Entity\Workflow;
/**
* Tests configuration dependencies in workflows.
*
* @coversDefaultClass \Drupal\workflows\Entity\Workflow
*
* @group workflows
*/
class WorkflowDependenciesTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'workflows', 'workflow_type_test', 'workflow_third_party_settings_test'];
/**
* Tests \Drupal\workflows\Entity\Workflow::onDependencyRemoval().
*/
public function testOnDependencyRemoval() {
// Create a workflow that has a dependency on a third party setting.
$workflow = Workflow::create(['id' => 'test3', 'type' => 'workflow_type_complex_test']);
$workflow->setThirdPartySetting('workflow_third_party_settings_test', 'key', 'value');
$workflow->save();
$this->assertSame(['workflow_third_party_settings_test', 'workflow_type_test'], $workflow->getDependencies()['module']);
// Uninstall workflow_third_party_settings_test to ensure
// \Drupal\workflows\Entity\Workflow::onDependencyRemoval() works as
// expected.
\Drupal::service('module_installer')->uninstall(['node', 'workflow_third_party_settings_test']);
$workflow = \Drupal::entityTypeManager()->getStorage('workflow')->loadUnchanged($workflow->id());
$this->assertSame(['workflow_type_test'], $workflow->getDependencies()['module']);
}
}