diff --git a/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml b/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml
index d8daa51..8ebd827 100644
--- a/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml
+++ b/core/modules/content_moderation/config/install/workflows.workflow.editorial.yml
@@ -5,59 +5,55 @@ dependencies:
- content_moderation
id: editorial
label: 'Editorial workflow'
-states:
- archived:
- label: Archived
- weight: 5
- draft:
- label: Draft
- weight: -5
- published:
- label: Published
- weight: 0
-transitions:
- archive:
- label: Archive
- from:
- - published
- to: archived
- weight: 2
- archived_draft:
- label: 'Restore to Draft'
- from:
- - archived
- to: draft
- weight: 3
- archived_published:
- label: Restore
- from:
- - archived
- to: published
- weight: 4
- create_new_draft:
- label: 'Create New Draft'
- from:
- - draft
- - published
- to: draft
- weight: 0
- publish:
- label: Publish
- from:
- - draft
- - published
- to: published
- weight: 1
type: content_moderation
type_settings:
states:
archived:
+ label: Archived
+ weight: 5
published: false
default_revision: true
draft:
+ label: Draft
published: false
default_revision: false
+ weight: -5
published:
+ label: Published
published: true
default_revision: true
+ weight: 0
+ transitions:
+ create_new_draft:
+ label: 'Create New Draft'
+ to: draft
+ weight: 0
+ from:
+ - draft
+ - published
+ publish:
+ label: Publish
+ to: published
+ weight: 1
+ from:
+ - draft
+ - published
+ archive:
+ label: Archive
+ from:
+ - published
+ to: archived
+ weight: 2
+ archived_draft:
+ label: 'Restore to Draft'
+ from:
+ - archived
+ to: draft
+ weight: 3
+ archived_published:
+ label: Restore
+ from:
+ - archived
+ to: published
+ weight: 4
entity_types: { }
diff --git a/core/modules/content_moderation/config/schema/content_moderation.schema.yml b/core/modules/content_moderation/config/schema/content_moderation.schema.yml
index b791b67..d38e858 100644
--- a/core/modules/content_moderation/config/schema/content_moderation.schema.yml
+++ b/core/modules/content_moderation/config/schema/content_moderation.schema.yml
@@ -6,22 +6,30 @@ views.filter.latest_revision:
type: string
label: 'Value'
+content_moderation.state:
+ type: workflows.state
+ mapping:
+ published:
+ type: boolean
+ label: 'Is published'
+ default_revision:
+ type: boolean
+ label: 'Is default revision'
+
workflow.type_settings.content_moderation:
type: mapping
mapping:
states:
type: sequence
- label: 'Additional state configuration for content moderation'
+ label: 'Content moderation states'
sequence:
- type: mapping
+ type: content_moderation.state
label: 'States'
- mapping:
- published:
- type: boolean
- label: 'Is published'
- default_revision:
- type: boolean
- label: 'Is default revision'
+ transitions:
+ type: sequence
+ sequence:
+ type: workflows.transition
+ label: 'Transitions'
entity_types:
type: sequence
label: 'Entity types'
diff --git a/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
index 4a41631..2641fd3 100644
--- a/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
+++ b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
@@ -95,13 +95,8 @@ public static function create(ContainerInterface $container, array $configuratio
* {@inheritdoc}
*/
public function initializeWorkflow(WorkflowInterface $workflow) {
- $workflow
- ->addState('draft', $this->t('Draft'))
- ->setStateWeight('draft', -5)
- ->addState('published', $this->t('Published'))
- ->setStateWeight('published', 0)
- ->addTransition('create_new_draft', $this->t('Create New Draft'), ['draft', 'published'], 'draft')
- ->addTransition('publish', $this->t('Publish'), ['draft', 'published'], 'published');
+ // @todo, do we need initializeWorkflow now that defaultConfiguration can
+ // initialise these.
return $workflow;
}
@@ -243,16 +238,39 @@ public function addEntityTypeAndBundle($entity_type_id, $bundle_id) {
* {@inheritdoc}
*/
public function defaultConfiguration() {
- // This plugin does not store anything per transition.
return [
'states' => [
'draft' => [
+ 'label' => 'Draft',
'published' => FALSE,
'default_revision' => FALSE,
+ 'weight' => 0,
],
'published' => [
+ 'label' => 'Published',
'published' => TRUE,
'default_revision' => TRUE,
+ 'weight' => 1,
+ ],
+ ],
+ 'transitions' => [
+ 'create_new_draft' => [
+ 'label' => 'Create New Draft',
+ 'to' => 'draft',
+ 'weight' => 0,
+ 'from' => [
+ 'draft',
+ 'published',
+ ],
+ ],
+ 'publish' => [
+ 'label' => 'Publish',
+ 'to' => 'published',
+ 'weight' => 1,
+ 'from' => [
+ 'draft',
+ 'published',
+ ],
],
],
'entity_types' => [],
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationPermissionsTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationPermissionsTest.php
index 3a19d22..5acf93c 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationPermissionsTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationPermissionsTest.php
@@ -55,37 +55,13 @@ public function permissionsTestCases() {
'id' => 'simple_workflow',
'label' => 'Simple Workflow',
'type' => 'content_moderation',
- 'transitions' => [
- 'publish' => [
- 'label' => 'Publish',
- 'from' => ['draft'],
- 'to' => 'published',
- 'weight' => 0,
- ],
- 'unpublish' => [
- 'label' => 'Unpublish',
- 'from' => ['published'],
- 'to' => 'draft',
- 'weight' => 0,
- ],
- ],
- 'states' => [
- 'draft' => [
- 'label' => 'Draft',
- 'weight' => -5,
- ],
- 'published' => [
- 'label' => 'Published',
- 'weight' => 0,
- ],
- ],
],
[
'use simple_workflow transition publish' => [
'title' => 'Use Publish transition from Simple Workflow workflow.',
],
- 'use simple_workflow transition unpublish' => [
- 'title' => 'Use Unpublish transition from Simple Workflow workflow.',
+ 'use simple_workflow transition create_new_draft' => [
+ 'title' => 'Use Create New Draft transition from Simple Workflow workflow.',
],
],
],
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php
index 220ac5d..e10756c 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php
@@ -37,9 +37,6 @@ class ContentModerationWorkflowTypeApiTest extends KernelTestBase {
protected function setUp() {
parent::setUp();
$this->workflow = Workflow::create(['id' => 'test', 'type' => 'content_moderation']);
- $this->workflow
- ->addState('draft', 'Draft')
- ->addState('published', 'Published');
}
/**
diff --git a/core/modules/content_moderation/tests/src/Unit/StateTransitionValidationTest.php b/core/modules/content_moderation/tests/src/Unit/StateTransitionValidationTest.php
index b7c3942..3e2e264 100644
--- a/core/modules/content_moderation/tests/src/Unit/StateTransitionValidationTest.php
+++ b/core/modules/content_moderation/tests/src/Unit/StateTransitionValidationTest.php
@@ -8,6 +8,7 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\content_moderation\StateTransitionValidation;
use Drupal\Tests\UnitTestCase;
+use Drupal\workflow_type_test\Plugin\WorkflowType\TestType;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\WorkflowTypeInterface;
use Drupal\workflows\WorkflowTypeManager;
@@ -62,14 +63,8 @@ protected function setUpModerationInformation(ContentEntityInterface $entity) {
// Create a container so that the plugin manager and workflow type can be
// mocked.
$container = new ContainerBuilder();
- $workflow_type = $this->prophesize(WorkflowTypeInterface::class);
- $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) {
- $this->getConfiguration()->willReturn($arguments[0]);
- });
- $workflow_type->decorateState(Argument::any())->willReturnArgument(0);
- $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
$workflow_manager = $this->prophesize(WorkflowTypeManager::class);
- $workflow_manager->createInstance('content_moderation', Argument::any())->willReturn($workflow_type->reveal());
+ $workflow_manager->createInstance('content_moderation', Argument::any())->willReturn(new TestType([], '', []));
$container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
\Drupal::setContainer($container);
diff --git a/core/modules/workflows/config/schema/workflows.schema.yml b/core/modules/workflows/config/schema/workflows.schema.yml
index e19eb6b..1232801 100644
--- a/core/modules/workflows/config/schema/workflows.schema.yml
+++ b/core/modules/workflows/config/schema/workflows.schema.yml
@@ -14,38 +14,32 @@ workflows.workflow.*:
type_settings:
type: workflow.type_settings.[%parent.type]
label: 'Custom settings for workflow type'
- states:
- type: sequence
- label: 'States'
- sequence:
- type: mapping
- label: 'State'
- mapping:
- label:
- type: label
- label: 'Label'
- weight:
- type: integer
- label: 'Weight'
- transitions:
+
+workflows.state:
+ type: mapping
+ mapping:
+ label:
+ type: label
+ label: 'Label'
+ weight:
+ type: integer
+ label: 'Weight'
+
+workflows.transition:
+ type: mapping
+ mapping:
+ label:
+ type: label
+ label: 'Transition label'
+ from:
type: sequence
- label: 'Transitions'
+ label: 'From state IDs'
sequence:
- type: mapping
- label: 'Transition from state to state'
- mapping:
- label:
- type: label
- label: 'Transition label'
- from:
- type: sequence
- label: 'From state IDs'
- sequence:
- type: string
- label: 'From state ID'
- to:
- type: string
- label: 'To state ID'
- weight:
- type: integer
- label: 'Weight'
+ type: string
+ label: 'From state ID'
+ to:
+ type: string
+ label: 'To state ID'
+ weight:
+ type: integer
+ label: 'Weight'
diff --git a/core/modules/workflows/src/Entity/Workflow.php b/core/modules/workflows/src/Entity/Workflow.php
index 51bdda2..6a7d6f7 100644
--- a/core/modules/workflows/src/Entity/Workflow.php
+++ b/core/modules/workflows/src/Entity/Workflow.php
@@ -54,8 +54,6 @@
* config_export = {
* "id",
* "label",
- * "states",
- * "transitions",
* "type",
* "type_settings"
* },
@@ -82,38 +80,6 @@ class Workflow extends ConfigEntityBase implements WorkflowInterface, EntityWith
protected $label;
/**
- * The states of the workflow.
- *
- * The array key is the machine name for the state. The structure of each
- * array item is:
- * @code
- * label: {translatable label}
- * weight: {integer value}
- * @endcode
- *
- * @var array
- */
- protected $states = [];
-
- /**
- * The permitted transitions of the workflow.
- *
- * The array key is the machine name for the transition. The machine name is
- * generated from the machine names of the states. The structure of each array
- * item is:
- * @code
- * from:
- * - {state machine name}
- * - {state machine name}
- * to: {state machine name}
- * label: {translatable label}
- * @endcode
- *
- * @var array
- */
- protected $transitions = [];
-
- /**
* The workflow type plugin ID.
*
* @see \Drupal\workflows\WorkflowTypeManager
@@ -148,399 +114,206 @@ public function preSave(EntityStorageInterface $storage) {
}
/**
- * {@inheritdoc}
+ * {@inheritDoc}
*/
- public function addState($state_id, $label) {
- if (isset($this->states[$state_id])) {
- throw new \InvalidArgumentException("The state '$state_id' already exists in workflow '{$this->id()}'");
- }
- if (preg_match('/[^a-z0-9_]+/', $state_id)) {
- throw new \InvalidArgumentException("The state ID '$state_id' must contain only lowercase letters, numbers, and underscores");
- }
- $this->states[$state_id] = [
- 'label' => $label,
- 'weight' => $this->getNextWeight($this->states),
- ];
- ksort($this->states);
- return $this;
+ public function getTypePlugin() {
+ return $this->getPluginCollection()->get($this->type);
}
/**
- * {@inheritdoc}
+ * {@inheritDoc}
*/
- public function hasState($state_id) {
- return isset($this->states[$state_id]);
+ public function getPluginCollections() {
+ return ['type_settings' => $this->getPluginCollection()];
}
/**
- * {@inheritdoc}
+ * Encapsulates the creation of the workflow's plugin collection.
+ *
+ * @return \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
+ * The workflow's plugin collection.
*/
- public function getStates($state_ids = NULL) {
- if ($state_ids === NULL) {
- $state_ids = array_keys($this->states);
- }
- /** @var \Drupal\workflows\StateInterface[] $states */
- $states = array_combine($state_ids, array_map([$this, 'getState'], $state_ids));
- if (count($states) > 1) {
- // Sort states by weight and then label.
- $weights = $labels = [];
- foreach ($states as $id => $state) {
- $weights[$id] = $state->weight();
- $labels[$id] = $state->label();
- }
- array_multisort(
- $weights, SORT_NUMERIC, SORT_ASC,
- $labels, SORT_NATURAL, SORT_ASC
- );
- $states = array_replace($weights, $states);
+ protected function getPluginCollection() {
+ if (!$this->pluginCollection && $this->type) {
+ $this->pluginCollection = new DefaultSingleLazyPluginCollection(\Drupal::service('plugin.manager.workflows.type'), $this->type, $this->type_settings);
}
- return $states;
+ return $this->pluginCollection;
}
/**
- * {@inheritdoc}
+ * Loads all workflows of the provided type.
+ *
+ * @param string $type
+ * The workflow type to load all workflows for.
+ *
+ * @return static[]
+ * An array of workflow objects of the provided workflow type, indexed by
+ * their IDs.
+ *
+ * @see \Drupal\workflows\Annotation\WorkflowType
*/
- public function getState($state_id) {
- if (!isset($this->states[$state_id])) {
- throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow '{$this->id()}'");
- }
- $state = new State(
- $this,
- $state_id,
- $this->states[$state_id]['label'],
- $this->states[$state_id]['weight']
- );
- return $this->getTypePlugin()->decorateState($state);
+ public static function loadMultipleByType($type) {
+ return self::loadMultiple(\Drupal::entityQuery('workflow')->condition('type', $type)->execute());
}
/**
* {@inheritdoc}
*/
- public function setStateLabel($state_id, $label) {
- if (!isset($this->states[$state_id])) {
- throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow '{$this->id()}'");
- }
- $this->states[$state_id]['label'] = $label;
- return $this;
+ public function status() {
+ // In order for a workflow to be usable it must have at least one state.
+ return !empty($this->status) && !empty($this->getTypePlugin()->getStates());
}
/**
* {@inheritdoc}
*/
- public function setStateWeight($state_id, $weight) {
- if (!isset($this->states[$state_id])) {
- throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow '{$this->id()}'");
- }
- $this->states[$state_id]['weight'] = $weight;
- return $this;
+ 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;
}
/**
* {@inheritdoc}
*/
- public function deleteState($state_id) {
- if (!isset($this->states[$state_id])) {
- throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow '{$this->id()}'");
- }
- if (count($this->states) === 1) {
- throw new \InvalidArgumentException("The state '$state_id' can not be deleted from workflow '{$this->id()}' as it is the only state");
- }
-
- foreach ($this->transitions as $transition_id => $transition) {
- $from_key = array_search($state_id, $transition['from'], TRUE);
- if ($from_key !== FALSE) {
- // Remove state from the from array.
- unset($transition['from'][$from_key]);
- }
- if (empty($transition['from']) || $transition['to'] === $state_id) {
- $this->deleteTransition($transition_id);
- }
- elseif ($from_key !== FALSE) {
- $this->setTransitionFromStates($transition_id, $transition['from']);
- }
- }
- unset($this->states[$state_id]);
- $this->getTypePlugin()->deleteState($state_id);
+ public function addState($state_id, $label) {
+ $this->getTypePlugin()->addState($state_id, $label);
return $this;
}
/**
* {@inheritdoc}
*/
- public function addTransition($transition_id, $label, array $from_state_ids, $to_state_id) {
- if (isset($this->transitions[$transition_id])) {
- throw new \InvalidArgumentException("The transition '$transition_id' already exists in workflow '{$this->id()}'");
- }
- if (preg_match('/[^a-z0-9_]+/', $transition_id)) {
- throw new \InvalidArgumentException("The transition ID '$transition_id' must contain only lowercase letters, numbers, and underscores");
- }
-
- if (!$this->hasState($to_state_id)) {
- throw new \InvalidArgumentException("The state '$to_state_id' does not exist in workflow '{$this->id()}'");
- }
- $this->transitions[$transition_id] = [
- 'label' => $label,
- 'from' => [],
- 'to' => $to_state_id,
- // Always add to the end.
- 'weight' => $this->getNextWeight($this->transitions),
- ];
-
- try {
- $this->setTransitionFromStates($transition_id, $from_state_ids);
- }
- catch (\InvalidArgumentException $e) {
- unset($this->transitions[$transition_id]);
- throw $e;
- }
-
- return $this;
+ public function hasState($state_id) {
+ return $this->getTypePlugin()->hasState($state_id);
}
/**
* {@inheritdoc}
*/
- public function getTransitions(array $transition_ids = NULL) {
- if ($transition_ids === NULL) {
- $transition_ids = array_keys($this->transitions);
- }
- /** @var \Drupal\workflows\TransitionInterface[] $transitions */
- $transitions = array_combine($transition_ids, array_map([$this, 'getTransition'], $transition_ids));
- if (count($transitions) > 1) {
- // Sort transitions by weights and then labels.
- $weights = $labels = [];
- foreach ($transitions as $id => $transition) {
- $weights[$id] = $transition->weight();
- $labels[$id] = $transition->label();
- }
- array_multisort(
- $weights, SORT_NUMERIC, SORT_ASC,
- $labels, SORT_NATURAL, SORT_ASC
- );
- $transitions = array_replace($weights, $transitions);
- }
- return $transitions;
+ public function getStates($state_ids = NULL) {
+ return $this->getTypePlugin()->getStates($state_ids);
}
/**
* {@inheritdoc}
*/
- public function getTransition($transition_id) {
- if (!isset($this->transitions[$transition_id])) {
- throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow '{$this->id()}'");
- }
- $transition = new Transition(
- $this,
- $transition_id,
- $this->transitions[$transition_id]['label'],
- $this->transitions[$transition_id]['from'],
- $this->transitions[$transition_id]['to'],
- $this->transitions[$transition_id]['weight']
- );
- return $this->getTypePlugin()->decorateTransition($transition);
+ public function getState($state_id) {
+ return $this->getTypePlugin()->getState($state_id);
}
/**
* {@inheritdoc}
*/
- public function hasTransition($transition_id) {
- return isset($this->transitions[$transition_id]);
+ public function setStateLabel($state_id, $label) {
+ $this->getTypePlugin()->setStateLabel($state_id, $label);
+ return $this;
}
/**
* {@inheritdoc}
*/
- public function getTransitionsForState($state_id, $direction = 'from') {
- $transition_ids = array_keys(array_filter($this->transitions, function ($transition) use ($state_id, $direction) {
- return in_array($state_id, (array) $transition[$direction], TRUE);
- }));
- return $this->getTransitions($transition_ids);
+ public function setStateWeight($state_id, $weight) {
+ $this->getTypePlugin()->setStateWeight($state_id, $weight);
+ return $this;
}
/**
* {@inheritdoc}
*/
- public function getTransitionFromStateToState($from_state_id, $to_state_id) {
- $transition_id = $this->getTransitionIdFromStateToState($from_state_id, $to_state_id);
- if (empty($transition_id)) {
- throw new \InvalidArgumentException("The transition from '$from_state_id' to '$to_state_id' does not exist in workflow '{$this->id()}'");
- }
- return $this->getTransition($transition_id);
+ public function deleteState($state_id) {
+ $this->getTypePlugin()->deleteState($state_id);
+ return $this;
}
/**
* {@inheritdoc}
*/
- public function hasTransitionFromStateToState($from_state_id, $to_state_id) {
- return !empty($this->getTransitionIdFromStateToState($from_state_id, $to_state_id));
- }
-
- /**
- * Gets the transition ID from state to state.
- *
- * @param string $from_state_id
- * The state ID to transition from.
- * @param string $to_state_id
- * The state ID to transition to.
- *
- * @return string|null
- * The transition ID, or NULL if no transition exists.
- */
- protected function getTransitionIdFromStateToState($from_state_id, $to_state_id) {
- foreach ($this->transitions as $transition_id => $transition) {
- if (in_array($from_state_id, $transition['from'], TRUE) && $transition['to'] === $to_state_id) {
- return $transition_id;
- }
- }
- return NULL;
+ public function getInitialState() {
+ return $this->getTypePlugin()->getInitialState($this);
}
/**
* {@inheritdoc}
*/
- public function setTransitionLabel($transition_id, $label) {
- if (isset($this->transitions[$transition_id])) {
- $this->transitions[$transition_id]['label'] = $label;
- }
- else {
- throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow '{$this->id()}'");
- }
+ public function addTransition($id, $label, array $from_state_ids, $to_state_id) {
+ $this->getTypePlugin()->addTransition($id, $label, $from_state_ids, $to_state_id);
return $this;
}
/**
* {@inheritdoc}
*/
- public function setTransitionWeight($transition_id, $weight) {
- if (isset($this->transitions[$transition_id])) {
- $this->transitions[$transition_id]['weight'] = $weight;
- }
- else {
- throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow '{$this->id()}'");
- }
- return $this;
+ public function getTransition($transition_id) {
+ return $this->getTypePlugin()->getTransition($transition_id);
}
/**
* {@inheritdoc}
*/
- public function setTransitionFromStates($transition_id, array $from_state_ids) {
- if (!isset($this->transitions[$transition_id])) {
- throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow '{$this->id()}'");
- }
-
- // Ensure that the states exist.
- foreach ($from_state_ids as $from_state_id) {
- if (!$this->hasState($from_state_id)) {
- throw new \InvalidArgumentException("The state '$from_state_id' does not exist in workflow '{$this->id()}'");
- }
- if ($this->hasTransitionFromStateToState($from_state_id, $this->transitions[$transition_id]['to'])) {
- $transition = $this->getTransitionFromStateToState($from_state_id, $this->transitions[$transition_id]['to']);
- if ($transition_id !== $transition->id()) {
- throw new \InvalidArgumentException("The '{$transition->id()}' transition already allows '$from_state_id' to '{$this->transitions[$transition_id]['to']}' transitions in workflow '{$this->id()}'");
- }
- }
- }
-
- // Preserve the order of the state IDs in the from value and don't save any
- // keys.
- $from_state_ids = array_values($from_state_ids);
- sort($from_state_ids);
- $this->transitions[$transition_id]['from'] = $from_state_ids;
- ksort($this->transitions);
-
- return $this;
+ public function hasTransition($transition_id) {
+ return $this->getTypePlugin()->hasTransition($transition_id);
}
/**
* {@inheritdoc}
*/
- public function deleteTransition($transition_id) {
- if (isset($this->transitions[$transition_id])) {
- unset($this->transitions[$transition_id]);
- $this->getTypePlugin()->deleteTransition($transition_id);
- }
- else {
- throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow '{$this->id()}'");
- }
- return $this;
+ public function getTransitions(array $transition_ids = NULL) {
+ return $this->getTypePlugin()->getTransitions($transition_ids);
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
- public function getTypePlugin() {
- return $this->getPluginCollection()->get($this->type);
+ public function getTransitionsForState($state_id, $direction = 'from') {
+ return $this->getTypePlugin()->getTransitionsForState($state_id, $direction);
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
- public function getPluginCollections() {
- return ['type_settings' => $this->getPluginCollection()];
+ public function getTransitionFromStateToState($from_state_id, $to_state_id) {
+ return $this->getTypePlugin()->getTransitionFromStateToState($from_state_id, $to_state_id);
}
/**
- * Encapsulates the creation of the workflow's plugin collection.
- *
- * @return \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
- * The workflow's plugin collection.
+ * {@inheritdoc}
*/
- protected function getPluginCollection() {
- if (!$this->pluginCollection && $this->type) {
- $this->pluginCollection = new DefaultSingleLazyPluginCollection(\Drupal::service('plugin.manager.workflows.type'), $this->type, $this->type_settings);
- }
- return $this->pluginCollection;
+ public function hasTransitionFromStateToState($from_state_id, $to_state_id) {
+ return $this->getTypePlugin()->hasTransitionFromStateToState($from_state_id, $to_state_id);
}
/**
- * Loads all workflows of the provided type.
- *
- * @param string $type
- * The workflow type to load all workflows for.
- *
- * @return static[]
- * An array of workflow objects of the provided workflow type, indexed by
- * their IDs.
- *
- * @see \Drupal\workflows\Annotation\WorkflowType
+ * {@inheritdoc}
*/
- public static function loadMultipleByType($type) {
- return self::loadMultiple(\Drupal::entityQuery('workflow')->condition('type', $type)->execute());
+ public function setTransitionLabel($transition_id, $label) {
+ $this->getTypePlugin()->setTransitionLabel($transition_id, $label);
+ return $this;
}
/**
- * Gets the weight for a new state or transition.
- *
- * @param array $items
- * An array of states or transitions information where each item has a
- * 'weight' key with a numeric value.
- *
- * @return int
- * The weight for a new item in the array so that it has the highest weight.
+ * {@inheritdoc}
*/
- protected function getNextWeight(array $items) {
- return array_reduce($items, function ($carry, $item) {
- return max($carry, $item['weight'] + 1);
- }, 0);
+ public function setTransitionWeight($transition_id, $weight) {
+ $this->getTypePlugin()->setTransitionWeight($transition_id, $weight);
+ return $this;
}
/**
* {@inheritdoc}
*/
- public function status() {
- // In order for a workflow to be usable it must have at least one state.
- return !empty($this->status) && !empty($this->states);
+ public function setTransitionFromStates($transition_id, array $from_state_ids) {
+ $this->getTypePlugin()->setTransitionFromStates($transition_id, $from_state_ids);
+ return $this;
}
/**
* {@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;
+ public function deleteTransition($transition_id) {
+ $this->getTypePlugin()->deleteTransition($transition_id);
+ return $this;
}
}
diff --git a/core/modules/workflows/src/Form/WorkflowStateAddForm.php b/core/modules/workflows/src/Form/WorkflowStateAddForm.php
index 0b36858..c7012c5 100644
--- a/core/modules/workflows/src/Form/WorkflowStateAddForm.php
+++ b/core/modules/workflows/src/Form/WorkflowStateAddForm.php
@@ -88,7 +88,7 @@ protected function copyFormValuesToEntity(EntityInterface $entity, array $form,
$entity->addState($values['id'], $values['label']);
if (isset($values['type_settings'])) {
$configuration = $entity->getTypePlugin()->getConfiguration();
- $configuration['states'][$values['id']] = $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
+ $configuration['states'][$values['id']] += $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
$entity->set('type_settings', $configuration);
}
}
diff --git a/core/modules/workflows/src/Form/WorkflowStateEditForm.php b/core/modules/workflows/src/Form/WorkflowStateEditForm.php
index f21508f..dea6f74 100644
--- a/core/modules/workflows/src/Form/WorkflowStateEditForm.php
+++ b/core/modules/workflows/src/Form/WorkflowStateEditForm.php
@@ -127,7 +127,7 @@ protected function copyFormValuesToEntity(EntityInterface $entity, array $form,
$entity->setStateLabel($values['id'], $values['label']);
if (isset($values['type_settings'])) {
$configuration = $entity->getTypePlugin()->getConfiguration();
- $configuration['states'][$values['id']] = $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
+ $configuration['states'][$values['id']] += $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
$entity->set('type_settings', $configuration);
}
}
diff --git a/core/modules/workflows/src/Form/WorkflowTransitionAddForm.php b/core/modules/workflows/src/Form/WorkflowTransitionAddForm.php
index fe3a406..a505e69 100644
--- a/core/modules/workflows/src/Form/WorkflowTransitionAddForm.php
+++ b/core/modules/workflows/src/Form/WorkflowTransitionAddForm.php
@@ -107,7 +107,7 @@ protected function copyFormValuesToEntity(EntityInterface $entity, array $form,
$entity->addTransition($values['id'], $values['label'], array_filter($values['from']), $values['to']);
if (isset($values['type_settings'])) {
$configuration = $entity->getTypePlugin()->getConfiguration();
- $configuration['transitions'][$values['id']] = $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
+ $configuration['transitions'][$values['id']] += $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
$entity->set('type_settings', $configuration);
}
}
diff --git a/core/modules/workflows/src/Form/WorkflowTransitionEditForm.php b/core/modules/workflows/src/Form/WorkflowTransitionEditForm.php
index 5bbabae..e3ba52d 100644
--- a/core/modules/workflows/src/Form/WorkflowTransitionEditForm.php
+++ b/core/modules/workflows/src/Form/WorkflowTransitionEditForm.php
@@ -130,7 +130,7 @@ protected function copyFormValuesToEntity(EntityInterface $entity, array $form,
$entity->setTransitionFromStates($values['id'], array_filter($values['from']));
if (isset($values['type_settings'])) {
$configuration = $entity->getTypePlugin()->getConfiguration();
- $configuration['transitions'][$values['id']] = $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
+ $configuration['transitions'][$values['id']] += $values['type_settings'][$entity->getTypePlugin()->getPluginId()];
$entity->set('type_settings', $configuration);
}
}
diff --git a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
index 34af735..3ca2941 100644
--- a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
+++ b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
@@ -7,7 +7,9 @@
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
+use Drupal\workflows\State;
use Drupal\workflows\StateInterface;
+use Drupal\workflows\Transition;
use Drupal\workflows\TransitionInterface;
use Drupal\workflows\WorkflowInterface;
use Drupal\workflows\WorkflowTypeInterface;
@@ -65,13 +67,6 @@ public function decorateState(StateInterface $state) {
/**
* {@inheritdoc}
*/
- public function deleteState($state_id) {
- unset($this->configuration['states'][$state_id]);
- }
-
- /**
- * {@inheritdoc}
- */
public function decorateTransition(TransitionInterface $transition) {
return $transition;
}
@@ -79,13 +74,6 @@ public function decorateTransition(TransitionInterface $transition) {
/**
* {@inheritdoc}
*/
- public function deleteTransition($transition_id) {
- unset($this->configuration['transitions'][$transition_id]);
- }
-
- /**
- * {@inheritdoc}
- */
public function buildStateConfigurationForm(FormStateInterface $form_state, WorkflowInterface $workflow, StateInterface $state = NULL) {
return [];
}
@@ -108,10 +96,7 @@ public function getConfiguration() {
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
- $this->configuration = NestedArray::mergeDeep(
- $this->defaultConfiguration(),
- $configuration
- );
+ $this->configuration = NestedArray::mergeDeepArray([$this->defaultConfiguration(), $configuration], TRUE);
}
/**
@@ -153,4 +138,338 @@ public function getInitialState(WorkflowInterface $workflow) {
return reset($ordered_states);
}
+ /**
+ * {@inheritdoc}
+ */
+ public function addState($state_id, $label) {
+ if (isset($this->configuration['states'][$state_id])) {
+ throw new \InvalidArgumentException("The state '$state_id' already exists in workflow.");
+ }
+ if (preg_match('/[^a-z0-9_]+/', $state_id)) {
+ throw new \InvalidArgumentException("The state ID '$state_id' must contain only lowercase letters, numbers, and underscores");
+ }
+ $this->configuration['states'][$state_id] = [
+ 'label' => $label,
+ 'weight' => $this->getNextWeight($this->configuration['states']),
+ ];
+ ksort($this->configuration['states']);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasState($state_id) {
+ $states = $this->getStates();
+ return isset($states[$state_id]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStates($state_ids = NULL) {
+ if ($state_ids === NULL) {
+ $state_ids = array_keys($this->configuration['states']);
+ }
+ /** @var \Drupal\workflows\StateInterface[] $states */
+ $states = array_combine($state_ids, array_map([$this, 'getState'], $state_ids));
+ if (count($states) > 1) {
+ // Sort states by weight and then label.
+ $weights = $labels = [];
+ foreach ($states as $id => $state) {
+ $weights[$id] = $state->weight();
+ $labels[$id] = $state->label();
+ }
+ array_multisort(
+ $weights, SORT_NUMERIC, SORT_ASC,
+ $labels, SORT_NATURAL, SORT_ASC
+ );
+ $states = array_replace($weights, $states);
+ }
+ return $states;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getState($state_id) {
+ if (!isset($this->configuration['states'][$state_id])) {
+ throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow.'");
+ }
+ $state = new State(
+ $this,
+ $state_id,
+ $this->configuration['states'][$state_id]['label'],
+ $this->configuration['states'][$state_id]['weight']
+ );
+ return $this->decorateState($state);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setStateLabel($state_id, $label) {
+ if (!isset($this->configuration['states'][$state_id])) {
+ throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow.'");
+ }
+ $this->configuration['states'][$state_id]['label'] = $label;
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setStateWeight($state_id, $weight) {
+ if (!isset($this->configuration['states'][$state_id])) {
+ throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow.'");
+ }
+ $this->configuration['states'][$state_id]['weight'] = $weight;
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteState($state_id) {
+ if (!isset($this->configuration['states'][$state_id])) {
+ throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow.'");
+ }
+ if (count($this->configuration['states']) === 1) {
+ throw new \InvalidArgumentException("The state '$state_id' can not be deleted from workflow as it is the only state.");
+ }
+
+ foreach ($this->configuration['transitions'] as $transition_id => $transition) {
+ $from_key = array_search($state_id, $transition['from'], TRUE);
+ if ($from_key !== FALSE) {
+ // Remove state from the from array.
+ unset($transition['from'][$from_key]);
+ }
+ if (empty($transition['from']) || $transition['to'] === $state_id) {
+ $this->deleteTransition($transition_id);
+ }
+ elseif ($from_key !== FALSE) {
+ $this->setTransitionFromStates($transition_id, $transition['from']);
+ }
+ }
+ unset($this->configuration['states'][$state_id]);
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addTransition($transition_id, $label, array $from_state_ids, $to_state_id) {
+ if (isset($this->configuration['transitions'][$transition_id])) {
+ throw new \InvalidArgumentException("The transition '$transition_id' already exists in workflow.'");
+ }
+ if (preg_match('/[^a-z0-9_]+/', $transition_id)) {
+ throw new \InvalidArgumentException("The transition ID '$transition_id' must contain only lowercase letters, numbers, and underscores.");
+ }
+
+ if (!$this->hasState($to_state_id)) {
+ throw new \InvalidArgumentException("The state '$to_state_id' does not exist in workflow.'");
+ }
+ $this->configuration['transitions'][$transition_id] = [
+ 'label' => $label,
+ 'from' => [],
+ 'to' => $to_state_id,
+ // Always add to the end.
+ 'weight' => $this->getNextWeight($this->configuration['transitions']),
+ ];
+
+ try {
+ $this->setTransitionFromStates($transition_id, $from_state_ids);
+ }
+ catch (\InvalidArgumentException $e) {
+ unset($this->configuration['transitions'][$transition_id]);
+ throw $e;
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTransitions(array $transition_ids = NULL) {
+ if ($transition_ids === NULL) {
+ $transition_ids = array_keys($this->configuration['transitions']);
+ }
+ /** @var \Drupal\workflows\TransitionInterface[] $transitions */
+ $transitions = array_combine($transition_ids, array_map([$this, 'getTransition'], $transition_ids));
+ if (count($transitions) > 1) {
+ // Sort transitions by weights and then labels.
+ $weights = $labels = [];
+ foreach ($transitions as $id => $transition) {
+ $weights[$id] = $transition->weight();
+ $labels[$id] = $transition->label();
+ }
+ array_multisort(
+ $weights, SORT_NUMERIC, SORT_ASC,
+ $labels, SORT_NATURAL, SORT_ASC
+ );
+ $transitions = array_replace($weights, $transitions);
+ }
+ return $transitions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTransition($transition_id) {
+ if (!isset($this->configuration['transitions'][$transition_id])) {
+ throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow.'");
+ }
+ $transition = new Transition(
+ $this,
+ $transition_id,
+ $this->configuration['transitions'][$transition_id]['label'],
+ $this->configuration['transitions'][$transition_id]['from'],
+ $this->configuration['transitions'][$transition_id]['to'],
+ $this->configuration['transitions'][$transition_id]['weight']
+ );
+ return $this->decorateTransition($transition);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasTransition($transition_id) {
+ return isset($this->configuration['transitions'][$transition_id]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTransitionsForState($state_id, $direction = 'from') {
+ $transition_ids = array_keys(array_filter($this->configuration['transitions'], function ($transition) use ($state_id, $direction) {
+ return in_array($state_id, (array) $transition[$direction], TRUE);
+ }));
+ return $this->getTransitions($transition_ids);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTransitionFromStateToState($from_state_id, $to_state_id) {
+ $transition_id = $this->getTransitionIdFromStateToState($from_state_id, $to_state_id);
+ if (empty($transition_id)) {
+ throw new \InvalidArgumentException("The transition from '$from_state_id' to '$to_state_id' does not exist in workflow.'");
+ }
+ return $this->getTransition($transition_id);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasTransitionFromStateToState($from_state_id, $to_state_id) {
+ return !empty($this->getTransitionIdFromStateToState($from_state_id, $to_state_id));
+ }
+
+ /**
+ * Gets the transition ID from state to state.
+ *
+ * @param string $from_state_id
+ * The state ID to transition from.
+ * @param string $to_state_id
+ * The state ID to transition to.
+ *
+ * @return string|null
+ * The transition ID, or NULL if no transition exists.
+ */
+ protected function getTransitionIdFromStateToState($from_state_id, $to_state_id) {
+ foreach ($this->configuration['transitions'] as $transition_id => $transition) {
+ if (in_array($from_state_id, $transition['from'], TRUE) && $transition['to'] === $to_state_id) {
+ return $transition_id;
+ }
+ }
+ return NULL;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTransitionLabel($transition_id, $label) {
+ if (isset($this->configuration['transitions'][$transition_id])) {
+ $this->configuration['transitions'][$transition_id]['label'] = $label;
+ }
+ else {
+ throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow.");
+ }
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTransitionWeight($transition_id, $weight) {
+ if (isset($this->configuration['transitions'][$transition_id])) {
+ $this->configuration['transitions'][$transition_id]['weight'] = $weight;
+ }
+ else {
+ throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow.'");
+ }
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setTransitionFromStates($transition_id, array $from_state_ids) {
+ if (!isset($this->configuration['transitions'][$transition_id])) {
+ throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow.");
+ }
+
+ // Ensure that the states exist.
+ foreach ($from_state_ids as $from_state_id) {
+ if (!$this->hasState($from_state_id)) {
+ throw new \InvalidArgumentException("The state '$from_state_id' does not exist in workflow.");
+ }
+ if ($this->hasTransitionFromStateToState($from_state_id, $this->configuration['transitions'][$transition_id]['to'])) {
+ $transition = $this->getTransitionFromStateToState($from_state_id, $this->configuration['transitions'][$transition_id]['to']);
+ if ($transition_id !== $transition->id()) {
+ throw new \InvalidArgumentException("The '{$transition->id()}' transition already allows '$from_state_id' to '{$this->configuration['transitions'][$transition_id]['to']}' transitions in workflow.");
+ }
+ }
+ }
+
+ // Preserve the order of the state IDs in the from value and don't save any
+ // keys.
+ $from_state_ids = array_values($from_state_ids);
+ sort($from_state_ids);
+ $this->configuration['transitions'][$transition_id]['from'] = $from_state_ids;
+ ksort($this->configuration['transitions']);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteTransition($transition_id) {
+ if (isset($this->configuration['transitions'][$transition_id])) {
+ unset($this->configuration['transitions'][$transition_id]);
+ }
+ else {
+ throw new \InvalidArgumentException("The transition '$transition_id' does not exist in workflow.");
+ }
+ return $this;
+ }
+
+ /**
+ * Gets the weight for a new state or transition.
+ *
+ * @param array $items
+ * An array of states or transitions information where each item has a
+ * 'weight' key with a numeric value.
+ *
+ * @return int
+ * The weight for a new item in the array so that it has the highest weight.
+ */
+ protected function getNextWeight(array $items) {
+ return array_reduce($items, function ($carry, $item) {
+ return max($carry, $item['weight'] + 1);
+ }, 0);
+ }
+
}
diff --git a/core/modules/workflows/src/State.php b/core/modules/workflows/src/State.php
index f8b4fae..f6a377b 100644
--- a/core/modules/workflows/src/State.php
+++ b/core/modules/workflows/src/State.php
@@ -51,7 +51,7 @@ class State implements StateInterface {
* @param int $weight
* The state's weight.
*/
- public function __construct(WorkflowInterface $workflow, $id, $label, $weight = 0) {
+ public function __construct(WorkflowTypeInterface $workflow, $id, $label, $weight = 0) {
$this->workflow = $workflow;
$this->id = $id;
$this->label = $label;
diff --git a/core/modules/workflows/src/Transition.php b/core/modules/workflows/src/Transition.php
index d8c21b6..38d5dba 100644
--- a/core/modules/workflows/src/Transition.php
+++ b/core/modules/workflows/src/Transition.php
@@ -69,7 +69,7 @@ class Transition implements TransitionInterface {
* @param int $weight
* (optional) The transition's weight. Defaults to 0.
*/
- public function __construct(WorkflowInterface $workflow, $id, $label, array $from_state_ids, $to_state_id, $weight = 0) {
+ public function __construct(WorkflowTypeInterface $workflow, $id, $label, array $from_state_ids, $to_state_id, $weight = 0) {
$this->workflow = $workflow;
$this->id = $id;
$this->label = $label;
diff --git a/core/modules/workflows/src/WorkflowInterface.php b/core/modules/workflows/src/WorkflowInterface.php
index 4f241c3..7b106c5 100644
--- a/core/modules/workflows/src/WorkflowInterface.php
+++ b/core/modules/workflows/src/WorkflowInterface.php
@@ -23,6 +23,8 @@
*
* @return \Drupal\workflows\WorkflowInterface
* The workflow entity.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function addState($state_id, $label);
@@ -34,6 +36,8 @@ public function addState($state_id, $label);
*
* @return bool
* TRUE if the workflow has a state with the provided ID, FALSE if not.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function hasState($state_id);
@@ -48,6 +52,8 @@ public function hasState($state_id);
*
* @throws \InvalidArgumentException
* Thrown if $state_ids contains a state ID that does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function getStates($state_ids = NULL);
@@ -62,6 +68,8 @@ public function getStates($state_ids = NULL);
*
* @throws \InvalidArgumentException
* Thrown if $state_id does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function getState($state_id);
@@ -75,6 +83,8 @@ public function getState($state_id);
*
* @return \Drupal\workflows\WorkflowInterface
* The workflow entity.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function setStateLabel($state_id, $label);
@@ -88,6 +98,8 @@ public function setStateLabel($state_id, $label);
*
* @return \Drupal\workflows\WorkflowInterface
* The workflow entity.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function setStateWeight($state_id, $weight);
@@ -102,10 +114,22 @@ public function setStateWeight($state_id, $weight);
*
* @throws \InvalidArgumentException
* Thrown if $state_id does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function deleteState($state_id);
/**
+ * Gets the initial state for the workflow.
+ *
+ * @return \Drupal\workflows\StateInterface
+ * The initial state.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
+ */
+ public function getInitialState();
+
+ /**
* Adds a transition to the workflow.
*
* @param string $id
@@ -122,6 +146,8 @@ public function deleteState($state_id);
*
* @throws \InvalidArgumentException
* Thrown if either state does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function addTransition($id, $label, array $from_state_ids, $to_state_id);
@@ -136,6 +162,8 @@ public function addTransition($id, $label, array $from_state_ids, $to_state_id);
*
* @throws \InvalidArgumentException
* Thrown if $transition_id does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function getTransition($transition_id);
@@ -147,6 +175,8 @@ public function getTransition($transition_id);
*
* @return bool
* TRUE if the transition exists, FALSE if not.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function hasTransition($transition_id);
@@ -162,6 +192,8 @@ public function hasTransition($transition_id);
*
* @throws \InvalidArgumentException
* Thrown if $transition_ids contains a transition ID that does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function getTransitions(array $transition_ids = NULL);
@@ -176,6 +208,8 @@ public function getTransitions(array $transition_ids = NULL);
*
* @return array
* The transition IDs for a state for the provided direction.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function getTransitionsForState($state_id, $direction = 'from');
@@ -192,6 +226,8 @@ public function getTransitionsForState($state_id, $direction = 'from');
*
* @throws \InvalidArgumentException
* Thrown if the transition does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function getTransitionFromStateToState($from_state_id, $to_state_id);
@@ -205,6 +241,8 @@ public function getTransitionFromStateToState($from_state_id, $to_state_id);
*
* @return bool
* TRUE if the transition exists, FALSE if not.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function hasTransitionFromStateToState($from_state_id, $to_state_id);
@@ -221,6 +259,8 @@ public function hasTransitionFromStateToState($from_state_id, $to_state_id);
*
* @throws \InvalidArgumentException
* Thrown if the transition does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function setTransitionLabel($transition_id, $label);
@@ -237,6 +277,8 @@ public function setTransitionLabel($transition_id, $label);
*
* @throws \InvalidArgumentException
* Thrown if the transition does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function setTransitionWeight($transition_id, $weight);
@@ -253,6 +295,8 @@ public function setTransitionWeight($transition_id, $weight);
*
* @throws \InvalidArgumentException
* Thrown if the transition does not exist or the states do not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function setTransitionFromStates($transition_id, array $from_state_ids);
@@ -267,6 +311,8 @@ public function setTransitionFromStates($transition_id, array $from_state_ids)
*
* @throws \InvalidArgumentException
* Thrown if the transition does not exist.
+ *
+ * @deprecated in Drupal 8.4.x and will be removed before 8.4.0.
*/
public function deleteTransition($transition_id);
diff --git a/core/modules/workflows/src/WorkflowTypeInterface.php b/core/modules/workflows/src/WorkflowTypeInterface.php
index 2412bf9..009f41c 100644
--- a/core/modules/workflows/src/WorkflowTypeInterface.php
+++ b/core/modules/workflows/src/WorkflowTypeInterface.php
@@ -68,14 +68,6 @@ public function checkWorkflowAccess(WorkflowInterface $entity, $operation, Accou
public function decorateState(StateInterface $state);
/**
- * React to the removal of a state from a workflow.
- *
- * @param string $state_id
- * The state ID of the state that is being removed.
- */
- public function deleteState($state_id);
-
- /**
* Decorates transitions so the WorkflowType can add additional information.
* @param \Drupal\workflows\TransitionInterface $transition
* The transition object to decorate.
@@ -86,14 +78,6 @@ public function deleteState($state_id);
public function decorateTransition(TransitionInterface $transition);
/**
- * React to the removal of a transition from a workflow.
- *
- * @param string $transition_id
- * The transition ID of the transition that is being removed.
- */
- public function deleteTransition($transition_id);
-
- /**
* Gets the initial state for the workflow.
*
* @param \Drupal\workflows\WorkflowInterface $workflow
@@ -170,4 +154,261 @@ public function getRequiredStates();
*/
public function onDependencyRemoval(array $dependencies);
+ /**
+ * Adds a state to the workflow.
+ *
+ * @param string $state_id
+ * The state's ID.
+ * @param string $label
+ * The state's label.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ */
+ public function addState($state_id, $label);
+
+ /**
+ * Determines if the workflow has a state with the provided ID.
+ *
+ * @param string $state_id
+ * The state's ID.
+ *
+ * @return bool
+ * TRUE if the workflow has a state with the provided ID, FALSE if not.
+ */
+ public function hasState($state_id);
+
+ /**
+ * Gets state objects for the provided state IDs.
+ *
+ * @param string[] $state_ids
+ * A list of state IDs to get. If NULL then all states will be returned.
+ *
+ * @return \Drupal\workflows\StateInterface[]
+ * An array of workflow states.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if $state_ids contains a state ID that does not exist.
+ */
+ public function getStates($state_ids = NULL);
+
+ /**
+ * Gets a workflow state.
+ *
+ * @param string $state_id
+ * The state's ID.
+ *
+ * @return \Drupal\workflows\StateInterface
+ * The workflow state.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if $state_id does not exist.
+ */
+ public function getState($state_id);
+
+ /**
+ * Sets a state's label.
+ *
+ * @param string $state_id
+ * The state ID to set the label for.
+ * @param string $label
+ * The state's label.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ */
+ public function setStateLabel($state_id, $label);
+
+ /**
+ * Sets a state's weight value.
+ *
+ * @param string $state_id
+ * The state ID to set the weight for.
+ * @param int $weight
+ * The state's weight.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ */
+ public function setStateWeight($state_id, $weight);
+
+ /**
+ * Deletes a state from the workflow.
+ *
+ * @param string $state_id
+ * The state ID to delete.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if $state_id does not exist.
+ */
+ public function deleteState($state_id);
+
+ /**
+ * Adds a transition to the workflow.
+ *
+ * @param string $id
+ * The transition ID.
+ * @param string $label
+ * The transition's label.
+ * @param array $from_state_ids
+ * The state IDs to transition from.
+ * @param string $to_state_id
+ * The state ID to transition to.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if either state does not exist.
+ */
+ public function addTransition($id, $label, array $from_state_ids, $to_state_id);
+
+ /**
+ * Gets a transition object for the provided transition ID.
+ *
+ * @param string $transition_id
+ * A transition ID.
+ *
+ * @return \Drupal\workflows\TransitionInterface
+ * The transition.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if $transition_id does not exist.
+ */
+ public function getTransition($transition_id);
+
+ /**
+ * Determines if a transition exists.
+ *
+ * @param string $transition_id
+ * The transition ID.
+ *
+ * @return bool
+ * TRUE if the transition exists, FALSE if not.
+ */
+ public function hasTransition($transition_id);
+
+ /**
+ * Gets transition objects for the provided transition IDs.
+ *
+ * @param string[] $transition_ids
+ * A list of transition IDs to get. If NULL then all transitions will be
+ * returned.
+ *
+ * @return \Drupal\workflows\TransitionInterface[]
+ * An array of transition objects.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if $transition_ids contains a transition ID that does not exist.
+ */
+ public function getTransitions(array $transition_ids = NULL);
+
+ /**
+ * Gets the transition IDs for a state for the provided direction.
+ *
+ * @param $state_id
+ * The state to get transitions for.
+ * @param string $direction
+ * (optional) The direction of the transition. Defaults to 'from'. Possible
+ * values are: 'from' and 'to'.
+ *
+ * @return array
+ * The transition IDs for a state for the provided direction.
+ */
+ public function getTransitionsForState($state_id, $direction = 'from');
+
+ /**
+ * Gets a transition from state to state.
+ *
+ * @param string $from_state_id
+ * The state ID to transition from.
+ * @param string $to_state_id
+ * The state ID to transition to.
+ *
+ * @return \Drupal\workflows\TransitionInterface
+ * The transitions.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if the transition does not exist.
+ */
+ public function getTransitionFromStateToState($from_state_id, $to_state_id);
+
+ /**
+ * Determines if a transition from state to state exists.
+ *
+ * @param string $from_state_id
+ * The state ID to transition from.
+ * @param string $to_state_id
+ * The state ID to transition to.
+ *
+ * @return bool
+ * TRUE if the transition exists, FALSE if not.
+ */
+ public function hasTransitionFromStateToState($from_state_id, $to_state_id);
+
+ /**
+ * Sets a transition's label.
+ *
+ * @param string $transition_id
+ * The transition ID.
+ * @param string $label
+ * The transition's label.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if the transition does not exist.
+ */
+ public function setTransitionLabel($transition_id, $label);
+
+ /**
+ * Sets a transition's weight.
+ *
+ * @param string $transition_id
+ * The transition ID.
+ * @param int $weight
+ * The transition's weight.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if the transition does not exist.
+ */
+ public function setTransitionWeight($transition_id, $weight);
+
+ /**
+ * Sets a transition's from states.
+ *
+ * @param string $transition_id
+ * The transition ID.
+ * @param array $from_state_ids
+ * The state IDs to transition from.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if the transition does not exist or the states do not exist.
+ */
+ public function setTransitionFromStates($transition_id, array $from_state_ids);
+
+ /**
+ * Deletes a transition.
+ *
+ * @param string $transition_id
+ * The transition ID.
+ *
+ * @return \Drupal\workflows\WorkflowTypeInterface
+ * The workflow type plugin.
+ *
+ * @throws \InvalidArgumentException
+ * Thrown if the transition does not exist.
+ */
+ public function deleteTransition($transition_id);
+
}
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml b/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml
index 1502edc..1d9e742 100644
--- a/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml
+++ b/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml
@@ -6,6 +6,10 @@ workflow.type_settings.workflow_type_test:
type: sequence
sequence:
type: ignore
+ transitions:
+ type: sequence
+ sequence:
+ type: ignore
workflow.type_settings.workflow_type_required_state_test:
type: mapping
@@ -15,6 +19,26 @@ workflow.type_settings.workflow_type_required_state_test:
type: sequence
sequence:
type: ignore
+ transitions:
+ type: sequence
+ sequence:
+ type: ignore
+
+# @todo, inline this straight into "workflow.type_settings.workflow_type_complex_test"
+# after https://www.drupal.org/node/2871746 is resolved.
+workflows.state.complex_test_state:
+ type: workflows.state
+ mapping:
+ extra:
+ type: string
+ label: 'Extra information'
+
+workflows.state.complex_test_transition:
+ type: workflows.transition
+ mapping:
+ extra:
+ type: string
+ label: 'Extra information'
workflow.type_settings.workflow_type_complex_test:
type: mapping
@@ -25,21 +49,24 @@ workflow.type_settings.workflow_type_complex_test:
label: 'Example setting'
states:
type: sequence
- label: 'Additional state configuration'
+ label: 'States'
sequence:
- type: mapping
+ type: workflows.state.complex_test_state
label: 'States'
- mapping:
- extra:
- type: string
- label: 'Extra information'
transitions:
type: sequence
- label: 'Additional transition configuration'
+ label: 'Transitions'
+ sequence:
+ label: 'Transitions'
+ type: workflows.state.complex_test_transition
+
+workflow.type_settings.predefined_states_workflow_test_type:
+ type: mapping
+ label: 'Predefined states workflow test type'
+ mapping:
+ transitions:
+ type: sequence
+ label: 'Transitions'
sequence:
- type: mapping
label: 'Transitions'
- mapping:
- extra:
- type: string
- label: 'Extra information'
+ type: workflows.transition
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/ComplexTestType.php b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/ComplexTestType.php
index 2cc25af..43d976c 100644
--- a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/ComplexTestType.php
+++ b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/ComplexTestType.php
@@ -28,7 +28,8 @@ class ComplexTestType extends WorkflowTypeFormBase {
*/
public function decorateState(StateInterface $state) {
if (isset($this->configuration['states'][$state->id()])) {
- $state = new DecoratedState($state, $this->configuration['states'][$state->id()]['extra']);
+ $extra = isset($this->configuration['states'][$state->id()]['extra']) ? $this->configuration['states'][$state->id()]['extra'] : '';
+ $state = new DecoratedState($state, $extra);
}
else {
$state = new DecoratedState($state);
@@ -41,7 +42,8 @@ public function decorateState(StateInterface $state) {
*/
public function decorateTransition(TransitionInterface $transition) {
if (isset($this->configuration['transitions'][$transition->id()])) {
- $transition = new DecoratedTransition($transition, $this->configuration['transitions'][$transition->id()]['extra']);
+ $extra = isset($this->configuration['transitions'][$transition->id()]['extra']) ? $this->configuration['transitions'][$transition->id()]['extra'] : '';
+ $transition = new DecoratedTransition($transition, $extra);
}
else {
$transition = new DecoratedTransition($transition);
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/PredefinedStatesWorkflowTestType.php b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/PredefinedStatesWorkflowTestType.php
new file mode 100644
index 0000000..3417477
--- /dev/null
+++ b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/PredefinedStatesWorkflowTestType.php
@@ -0,0 +1,90 @@
+ new State($this, 'pay_blinds', 'Pay Blinds'),
+ 'bet' => new State($this, 'bet', 'Bet'),
+ 'raise' => new State($this, 'raise', 'Raise'),
+ 'fold' => new State($this, 'fold', 'Fold'),
+ ], function($state) use ($state_ids) {
+ return is_array($state_ids) ? in_array($state->id(), $state_ids) : TRUE;
+ });
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getState($state_id) {
+ $states = $this->getStates();
+ if (!isset($states[$state_id])) {
+ throw new \InvalidArgumentException("The state '$state_id' does not exist in workflow.'");
+ }
+ return $states[$state_id];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addState($state_id, $label) {
+ // States cannot be added on this workflow.
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setStateLabel($state_id, $label) {
+ // States cannot be altered on this workflow.
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setStateWeight($state_id, $weight) {
+ // States cannot be altered on this workflow.
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function deleteState($state_id) {
+ // States cannot be deleted on this workflow.
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function defaultConfiguration() {
+ return [
+ 'transitions' => [],
+ ];
+ }
+
+}
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/RequiredStateTestType.php b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/RequiredStateTestType.php
index 4933557..a6d0695 100644
--- a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/RequiredStateTestType.php
+++ b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/RequiredStateTestType.php
@@ -34,12 +34,4 @@ public function initializeWorkflow(WorkflowInterface $workflow) {
return $workflow;
}
- /**
- * {@inheritdoc}
- */
- public function defaultConfiguration() {
- // No configuration is stored for the test type.
- return [];
- }
-
}
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/TestType.php b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/TestType.php
index 2ff68a8..ddd074a 100644
--- a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/TestType.php
+++ b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/TestType.php
@@ -17,14 +17,6 @@ class TestType extends WorkflowTypeBase {
/**
* {@inheritdoc}
*/
- public function defaultConfiguration() {
- // No configuration is stored for the test type.
- return [];
- }
-
- /**
- * {@inheritdoc}
- */
public function getRequiredStates() {
// Normally this is obtained from the annotation but we get from state to
// allow dynamic testing.
diff --git a/core/modules/workflows/tests/src/Kernel/PredefinedWorkflowTypeTest.php b/core/modules/workflows/tests/src/Kernel/PredefinedWorkflowTypeTest.php
new file mode 100644
index 0000000..f3f0b57
--- /dev/null
+++ b/core/modules/workflows/tests/src/Kernel/PredefinedWorkflowTypeTest.php
@@ -0,0 +1,52 @@
+ 'aces',
+ 'label' => 'Aces Workflow',
+ 'type' => 'predefined_states_workflow_test_type',
+ 'transitions' => [
+ 'bet' => [
+ 'label' => 'Bet',
+ 'from' => [
+ 'pay_blinds',
+ ],
+ 'to' => 'bet',
+ ],
+ 'raise' => [
+ 'label' => 'Raise',
+ 'from' => [
+ 'pay_blinds',
+ ],
+ 'to' => 'raise',
+ ],
+ ],
+ ]);
+ $workflow->save();
+
+ // No states configuration is stored for this workflow.
+ $configuration = $workflow->getTypePlugin()->getConfiguration();
+ $this->assertFalse(isset($configuration['states']));
+ }
+
+}
diff --git a/core/modules/workflows/tests/src/Kernel/RequiredStatesTest.php b/core/modules/workflows/tests/src/Kernel/RequiredStatesTest.php
index c9ef715..d99d308 100644
--- a/core/modules/workflows/tests/src/Kernel/RequiredStatesTest.php
+++ b/core/modules/workflows/tests/src/Kernel/RequiredStatesTest.php
@@ -106,11 +106,11 @@ public function testChangeRequiredStateAPI() {
'cooked',
'fresh',
'rotten',
- ], array_keys($workflow->get('states')));
+ ], array_keys($workflow->getTypePlugin()->getConfiguration()['states']));
$this->assertSame([
'cook',
'rot',
- ], array_keys($workflow->get('transitions')));
+ ], array_keys($workflow->getTypePlugin()->getConfiguration()['transitions']));
// Ensure that transitions can be deleted.
$workflow->deleteTransition('rot')->save();
diff --git a/core/modules/workflows/tests/src/Unit/StateTest.php b/core/modules/workflows/tests/src/Unit/StateTest.php
index ae9fc46..548225d 100644
--- a/core/modules/workflows/tests/src/Unit/StateTest.php
+++ b/core/modules/workflows/tests/src/Unit/StateTest.php
@@ -4,6 +4,7 @@
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
+use Drupal\workflow_type_test\Plugin\WorkflowType\TestType;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\State;
use Drupal\workflows\WorkflowInterface;
@@ -19,28 +20,6 @@
class StateTest extends UnitTestCase {
/**
- * Sets up the Workflow Type manager so that workflow entities can be used.
- */
- protected function setUp() {
- parent::setUp();
- // Create a container so that the plugin manager and workflow type can be
- // mocked.
- $container = new ContainerBuilder();
- $workflow_type = $this->prophesize(WorkflowTypeInterface::class);
- $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) {
- $this->getConfiguration()->willReturn($arguments[0]);
- });
- $workflow_type->decorateState(Argument::any())->willReturnArgument(0);
- $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
- $workflow_type->deleteState(Argument::any())->willReturn(NULL);
- $workflow_type->deleteTransition(Argument::any())->willReturn(NULL);
- $workflow_manager = $this->prophesize(WorkflowTypeManager::class);
- $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal());
- $container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
- \Drupal::setContainer($container);
- }
-
- /**
* @covers ::__construct
* @covers ::id
* @covers ::label
@@ -48,7 +27,7 @@ protected function setUp() {
*/
public function testGetters() {
$state = new State(
- $this->prophesize(WorkflowInterface::class)->reveal(),
+ $this->prophesize(WorkflowTypeInterface::class)->reveal(),
'draft',
'Draft',
3
@@ -62,16 +41,16 @@ public function testGetters() {
* @covers ::canTransitionTo
*/
public function testCanTransitionTo() {
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
- $workflow
+ $workflow_type = new TestType([], '', []);
+ $workflow_type
->addState('draft', 'Draft')
->addState('published', 'Published')
->addTransition('publish', 'Publish', ['draft'], 'published');
- $state = $workflow->getState('draft');
+ $state = $workflow_type->getState('draft');
$this->assertTrue($state->canTransitionTo('published'));
$this->assertFalse($state->canTransitionTo('some_other_state'));
- $workflow->deleteTransition('publish');
+ $workflow_type->deleteTransition('publish');
$this->assertFalse($state->canTransitionTo('published'));
}
@@ -79,12 +58,12 @@ public function testCanTransitionTo() {
* @covers ::getTransitionTo
*/
public function testGetTransitionTo() {
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
- $workflow
+ $workflow_type = new TestType([], '', []);
+ $workflow_type
->addState('draft', 'Draft')
->addState('published', 'Published')
->addTransition('publish', 'Publish', ['draft'], 'published');
- $state = $workflow->getState('draft');
+ $state = $workflow_type->getState('draft');
$transition = $state->getTransitionTo('published');
$this->assertEquals('Publish', $transition->label());
}
@@ -94,9 +73,9 @@ public function testGetTransitionTo() {
*/
public function testGetTransitionToException() {
$this->setExpectedException(\InvalidArgumentException::class, "Can not transition to 'published' state");
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
- $workflow->addState('draft', 'Draft');
- $state = $workflow->getState('draft');
+ $workflow_type = new TestType([], '', []);
+ $workflow_type->addState('draft', 'Draft');
+ $state = $workflow_type->getState('draft');
$state->getTransitionTo('published');
}
@@ -104,15 +83,15 @@ public function testGetTransitionToException() {
* @covers ::getTransitions
*/
public function testGetTransitions() {
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
- $workflow
+ $workflow_type = new TestType([], '', []);
+ $workflow_type
->addState('draft', 'Draft')
->addState('published', 'Published')
->addState('archived', 'Archived')
->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft')
->addTransition('publish', 'Publish', ['draft'], 'published')
->addTransition('archive', 'Archive', ['published'], 'archived');
- $state = $workflow->getState('draft');
+ $state = $workflow_type->getState('draft');
$transitions = $state->getTransitions();
$this->assertCount(2, $transitions);
$this->assertEquals('Create new draft', $transitions['create_new_draft']->label());
@@ -123,10 +102,10 @@ public function testGetTransitions() {
* @covers ::labelCallback
*/
public function testLabelCallback() {
- $workflow = $this->prophesize(WorkflowInterface::class)->reveal();
+ $workflow_type = $this->prophesize(WorkflowTypeInterface::class)->reveal();
$states = [
- new State($workflow, 'draft', 'Draft'),
- new State($workflow, 'published', 'Published'),
+ new State($workflow_type, 'draft', 'Draft'),
+ new State($workflow_type, 'published', 'Published'),
];
$this->assertEquals(['Draft', 'Published'], array_map([State::class, 'labelCallback'], $states));
}
diff --git a/core/modules/workflows/tests/src/Unit/TransitionTest.php b/core/modules/workflows/tests/src/Unit/TransitionTest.php
index c343fed..be59c94 100644
--- a/core/modules/workflows/tests/src/Unit/TransitionTest.php
+++ b/core/modules/workflows/tests/src/Unit/TransitionTest.php
@@ -4,6 +4,7 @@
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
+use Drupal\workflow_type_test\Plugin\WorkflowType\TestType;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\Transition;
use Drupal\workflows\WorkflowInterface;
@@ -19,33 +20,13 @@
class TransitionTest extends UnitTestCase {
/**
- * Sets up the Workflow Type manager so that workflow entities can be used.
- */
- protected function setUp() {
- parent::setUp();
- // Create a container so that the plugin manager and workflow type can be
- // mocked.
- $container = new ContainerBuilder();
- $workflow_type = $this->prophesize(WorkflowTypeInterface::class);
- $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) {
- $this->getConfiguration()->willReturn($arguments[0]);
- });
- $workflow_type->decorateState(Argument::any())->willReturnArgument(0);
- $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
- $workflow_manager = $this->prophesize(WorkflowTypeManager::class);
- $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal());
- $container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
- \Drupal::setContainer($container);
- }
-
- /**
* @covers ::__construct
* @covers ::id
* @covers ::label
*/
public function testGetters() {
$state = new Transition(
- $this->prophesize(WorkflowInterface::class)->reveal(),
+ $this->prophesize(WorkflowTypeInterface::class)->reveal(),
'draft_published',
'Publish',
['draft'],
@@ -60,7 +41,7 @@ public function testGetters() {
* @covers ::to
*/
public function testFromAndTo() {
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
+ $workflow = new TestType([], '', []);
$workflow
->addState('draft', 'Draft')
->addState('published', 'Published')
diff --git a/core/modules/workflows/tests/src/Unit/WorkflowTest.php b/core/modules/workflows/tests/src/Unit/WorkflowTest.php
index 51cb912..67c8205 100644
--- a/core/modules/workflows/tests/src/Unit/WorkflowTest.php
+++ b/core/modules/workflows/tests/src/Unit/WorkflowTest.php
@@ -4,6 +4,7 @@
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
+use Drupal\workflow_type_test\Plugin\WorkflowType\TestType;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\State;
use Drupal\workflows\Transition;
@@ -26,14 +27,8 @@ protected function setUp() {
// Create a container so that the plugin manager and workflow type can be
// mocked.
$container = new ContainerBuilder();
- $workflow_type = $this->prophesize(WorkflowTypeInterface::class);
- $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) {
- $this->getConfiguration()->willReturn($arguments[0]);
- });
- $workflow_type->decorateState(Argument::any())->willReturnArgument(0);
- $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
$workflow_manager = $this->prophesize(WorkflowTypeManager::class);
- $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal());
+ $workflow_manager->createInstance('test_type', Argument::any())->willReturn(new TestType([], '', []));
$container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
\Drupal::setContainer($container);
}
@@ -64,7 +59,7 @@ public function testAddAndHasState() {
* @covers ::addState
*/
public function testAddStateException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' already exists in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' already exists in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('draft', 'Draft');
$workflow->addState('draft', 'Draft');
@@ -99,7 +94,7 @@ public function testGetStates() {
'archived',
'draft',
'published',
- ], array_keys($workflow->get('states')));
+ ], array_keys($workflow->getTypePlugin()->getConfiguration()['states']));
// Ensure we're returning state objects.
$this->assertInstanceOf(State::class, $workflow->getStates()['draft']);
@@ -126,7 +121,7 @@ public function testGetStates() {
* @covers ::getStates
*/
public function testGetStatesException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'state_that_does_not_exist' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'state_that_does_not_exist' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->getStates(['state_that_does_not_exist']);
}
@@ -163,7 +158,7 @@ public function testGetState() {
* @covers ::getState
*/
public function testGetStateException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'state_that_does_not_exist' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'state_that_does_not_exist' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->getState('state_that_does_not_exist');
}
@@ -183,7 +178,7 @@ public function testSetStateLabel() {
* @covers ::setStateLabel
*/
public function testSetStateLabelException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->setStateLabel('draft', 'Draft');
}
@@ -203,7 +198,7 @@ public function testSetStateWeight() {
* @covers ::setStateWeight
*/
public function testSetStateWeightException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->setStateWeight('draft', 10);
}
@@ -212,43 +207,25 @@ public function testSetStateWeightException() {
* @covers ::deleteState
*/
public function testDeleteState() {
- // Create a container so that the plugin manager and workflow type can be
- // mocked and test that
- // \Drupal\workflows\WorkflowTypeInterface::deleteState() is called
- // correctly.
- $container = new ContainerBuilder();
- $workflow_type = $this->prophesize(WorkflowTypeInterface::class);
- $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) {
- $this->getConfiguration()->willReturn($arguments[0]);
- });
- $workflow_type->decorateState(Argument::any())->willReturnArgument(0);
- $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
- $workflow_type->deleteState('draft')->shouldBeCalled();
- $workflow_type->deleteTransition('create_new_draft')->shouldBeCalled();
- $workflow_manager = $this->prophesize(WorkflowTypeManager::class);
- $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal());
- $container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
- \Drupal::setContainer($container);
-
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
- $workflow
+ $workflow_type = new TestType([], '', []);
+ $workflow_type
->addState('draft', 'Draft')
->addState('published', 'Published')
->addTransition('publish', 'Publish', ['draft', 'published'], 'published')
->addTransition('create_new_draft', 'Create new draft', ['draft', 'published'], 'draft');
- $this->assertCount(2, $workflow->getStates());
- $this->assertCount(2, $workflow->getState('published')->getTransitions());
- $workflow->deleteState('draft');
- $this->assertFalse($workflow->hasState('draft'));
- $this->assertCount(1, $workflow->getStates());
- $this->assertCount(1, $workflow->getState('published')->getTransitions());
+ $this->assertCount(2, $workflow_type->getStates());
+ $this->assertCount(2, $workflow_type->getState('published')->getTransitions());
+ $workflow_type->deleteState('draft');
+ $this->assertFalse($workflow_type->hasState('draft'));
+ $this->assertCount(1, $workflow_type->getStates());
+ $this->assertCount(1, $workflow_type->getState('published')->getTransitions());
}
/**
* @covers ::deleteState
*/
public function testDeleteStateException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->deleteState('draft');
}
@@ -257,7 +234,7 @@ public function testDeleteStateException() {
* @covers ::deleteState
*/
public function testDeleteOnlyStateException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' can not be deleted from workflow 'test' as it is the only state");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' can not be deleted from workflow as it is the only state");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('draft', 'Draft');
$workflow->deleteState('draft');
@@ -290,7 +267,7 @@ public function testAddTransition() {
* @covers ::addTransition
*/
public function testAddTransitionDuplicateException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition 'publish' already exists in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition 'publish' already exists in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('published', 'Published');
$workflow->addTransition('publish', 'Publish', ['published'], 'published');
@@ -311,7 +288,7 @@ public function testAddTransitionInvalidIdException() {
* @covers ::addTransition
*/
public function testAddTransitionMissingFromException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'draft' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('published', 'Published');
$workflow->addTransition('publish', 'Publish', ['draft'], 'published');
@@ -321,7 +298,7 @@ public function testAddTransitionMissingFromException() {
* @covers ::addTransition
*/
public function testAddTransitionDuplicateTransitionStatesException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The 'publish' transition already allows 'draft' to 'published' transitions in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The 'publish' transition already allows 'draft' to 'published' transitions in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow
->addState('draft', 'Draft')
@@ -351,7 +328,7 @@ public function testAddTransitionConsistentAfterFromCatch() {
* @covers ::addTransition
*/
public function testAddTransitionMissingToException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'published' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'published' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('draft', 'Draft');
$workflow->addTransition('publish', 'Publish', ['draft'], 'published');
@@ -376,7 +353,7 @@ public function testGetTransitions() {
->addTransition('a_a', 'A to A', ['a'], 'a');
// Transitions are stored in alphabetical key order in configuration.
- $this->assertArrayEquals(['a_a', 'a_b'], array_keys($workflow->get('transitions')));
+ $this->assertArrayEquals(['a_a', 'a_b'], array_keys($workflow->getTypePlugin()->getConfiguration()['transitions']));
// Ensure we're returning transition objects.
$this->assertInstanceOf(Transition::class, $workflow->getTransitions()['a_a']);
@@ -429,7 +406,7 @@ public function testGetTransition() {
* @covers ::getTransition
*/
public function testGetTransitionException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition 'transition_that_does_not_exist' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition 'transition_that_does_not_exist' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->getTransition('transition_that_does_not_exist');
}
@@ -482,7 +459,7 @@ public function testGetTransitionFromStateToState() {
* @covers ::getTransitionFromStateToState
*/
public function testGetTransitionFromStateToStateException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition from 'archived' to 'archived' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition from 'archived' to 'archived' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
// By default states are ordered in the order added.
$workflow
@@ -514,7 +491,7 @@ public function testSetTransitionLabel() {
* @covers ::setTransitionLabel
*/
public function testSetTransitionLabelException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('published', 'Published');
$workflow->setTransitionLabel('draft-published', 'Publish');
@@ -538,7 +515,7 @@ public function testSetTransitionWeight() {
* @covers ::setTransitionWeight
*/
public function testSetTransitionWeightException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('published', 'Published');
$workflow->setTransitionWeight('draft-published', 10);
@@ -572,7 +549,7 @@ public function testSetTransitionFromStates() {
* @covers ::setTransitionFromStates
*/
public function testSetTransitionFromStatesMissingTransition() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition 'test' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition 'test' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow
->addState('draft', 'Draft')
@@ -587,7 +564,7 @@ public function testSetTransitionFromStatesMissingTransition() {
* @covers ::setTransitionFromStates
*/
public function testSetTransitionFromStatesMissingState() {
- $this->setExpectedException(\InvalidArgumentException::class, "The state 'published' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The state 'published' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow
->addState('draft', 'Draft')
@@ -601,7 +578,7 @@ public function testSetTransitionFromStatesMissingState() {
* @covers ::setTransitionFromStates
*/
public function testSetTransitionFromStatesAlreadyExists() {
- $this->setExpectedException(\InvalidArgumentException::class, "The 'create_new_draft' transition already allows 'draft' to 'draft' transitions in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The 'create_new_draft' transition already allows 'draft' to 'draft' transitions in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow
->addState('draft', 'Draft')
@@ -617,40 +594,23 @@ public function testSetTransitionFromStatesAlreadyExists() {
* @covers ::deleteTransition
*/
public function testDeleteTransition() {
- // Create a container so that the plugin manager and workflow type can be
- // mocked and test that
- // \Drupal\workflows\WorkflowTypeInterface::deleteState() is called
- // correctly.
- $container = new ContainerBuilder();
- $workflow_type = $this->prophesize(WorkflowTypeInterface::class);
- $workflow_type->setConfiguration(Argument::any())->will(function ($arguments) {
- $this->getConfiguration()->willReturn($arguments[0]);
- });
- $workflow_type->decorateState(Argument::any())->willReturnArgument(0);
- $workflow_type->decorateTransition(Argument::any())->willReturnArgument(0);
- $workflow_type->deleteTransition('publish')->shouldBeCalled();
- $workflow_manager = $this->prophesize(WorkflowTypeManager::class);
- $workflow_manager->createInstance('test_type', Argument::any())->willReturn($workflow_type->reveal());
- $container->set('plugin.manager.workflows.type', $workflow_manager->reveal());
- \Drupal::setContainer($container);
-
- $workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
- $workflow
+ $workflow_type = new TestType([], '', []);
+ $workflow_type
->addState('draft', 'Draft')
->addState('published', 'Published')
->addTransition('create_new_draft', 'Create new draft', ['draft'], 'draft')
->addTransition('publish', 'Publish', ['draft'], 'published');
- $this->assertTrue($workflow->getState('draft')->canTransitionTo('published'));
- $workflow->deleteTransition('publish');
- $this->assertFalse($workflow->getState('draft')->canTransitionTo('published'));
- $this->assertTrue($workflow->getState('draft')->canTransitionTo('draft'));
+ $this->assertTrue($workflow_type->getState('draft')->canTransitionTo('published'));
+ $workflow_type->deleteTransition('publish');
+ $this->assertFalse($workflow_type->getState('draft')->canTransitionTo('published'));
+ $this->assertTrue($workflow_type->getState('draft')->canTransitionTo('draft'));
}
/**
* @covers ::deleteTransition
*/
public function testDeleteTransitionException() {
- $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow 'test'");
+ $this->setExpectedException(\InvalidArgumentException::class, "The transition 'draft-published' does not exist in workflow.");
$workflow = new Workflow(['id' => 'test', 'type' => 'test_type'], 'workflow');
$workflow->addState('published', 'Published');
$workflow->deleteTransition('draft-published');