diff --git a/core/modules/content_moderation/content_moderation.module b/core/modules/content_moderation/content_moderation.module
index 77d822b..31cc6c9 100644
--- a/core/modules/content_moderation/content_moderation.module
+++ b/core/modules/content_moderation/content_moderation.module
@@ -63,15 +63,6 @@ function content_moderation_entity_type_alter(array &$entity_types) {
}
/**
- * Implements hook_entity_operation().
- */
-function content_moderation_entity_operation(EntityInterface $entity) {
- return \Drupal::service('class_resolver')
- ->getInstanceFromDefinition(EntityTypeInfo::class)
- ->entityOperation($entity);
-}
-
-/**
* Implements hook_entity_presave().
*/
function content_moderation_entity_presave(EntityInterface $entity) {
diff --git a/core/modules/content_moderation/content_moderation.routing.yml b/core/modules/content_moderation/content_moderation.routing.yml
new file mode 100644
index 0000000..b511ab3
--- /dev/null
+++ b/core/modules/content_moderation/content_moderation.routing.yml
@@ -0,0 +1,7 @@
+workflow.type_edit_form:
+ path: '/admin/config/workflow/workflows/manage/{workflow}/type/{entity_type_id}'
+ defaults:
+ _form: '\Drupal\content_moderation\Form\WorkflowTypeEditForm'
+ _title_callback: '\Drupal\content_moderation\Form\WorkflowTypeEditForm::getTitle'
+ requirements:
+ _permission: 'administer workflows'
diff --git a/core/modules/content_moderation/src/EntityTypeInfo.php b/core/modules/content_moderation/src/EntityTypeInfo.php
index f11e471..1ccfbf5 100644
--- a/core/modules/content_moderation/src/EntityTypeInfo.php
+++ b/core/modules/content_moderation/src/EntityTypeInfo.php
@@ -21,9 +21,7 @@
use Drupal\content_moderation\Entity\Handler\BlockContentModerationHandler;
use Drupal\content_moderation\Entity\Handler\ModerationHandler;
use Drupal\content_moderation\Entity\Handler\NodeModerationHandler;
-use Drupal\content_moderation\Form\BundleModerationConfigurationForm;
use Drupal\content_moderation\Routing\EntityModerationRouteProvider;
-use Drupal\content_moderation\Routing\EntityTypeModerationRouteProvider;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -127,11 +125,6 @@ public function entityTypeAlter(array &$entity_types) {
// The ContentModerationState entity type should never be moderated.
if ($entity_type->isRevisionable() && $entity_type_id != 'content_moderation_state') {
$entity_types[$entity_type_id] = $this->addModerationToEntityType($entity_type);
- // Add additional moderation support to entity types whose bundles are
- // managed by a config entity type.
- if ($entity_type->getBundleEntityType()) {
- $entity_types[$entity_type->getBundleEntityType()] = $this->addModerationToBundleEntityType($entity_types[$entity_type->getBundleEntityType()]);
- }
}
}
}
@@ -170,67 +163,6 @@ protected function addModerationToEntityType(ContentEntityTypeInterface $type) {
}
/**
- * Configures moderation configuration support on a entity type definition.
- *
- * That "configuration support" includes a configuration form, a hypermedia
- * link, and a route provider to tie it all together. There's also a
- * moderation handler for per-entity-type variation.
- *
- * @param \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $type
- * The config entity definition to modify.
- *
- * @return \Drupal\Core\Config\Entity\ConfigEntityTypeInterface
- * The modified config entity definition.
- */
- protected function addModerationToBundleEntityType(ConfigEntityTypeInterface $type) {
- if ($type->hasLinkTemplate('edit-form') && !$type->hasLinkTemplate('moderation-form')) {
- $type->setLinkTemplate('moderation-form', $type->getLinkTemplate('edit-form') . '/moderation');
- }
-
- if (!$type->getFormClass('moderation')) {
- $type->setFormClass('moderation', BundleModerationConfigurationForm::class);
- }
-
- // @todo Core forgot to add a direct way to manipulate route_provider, so
- // we have to do it the sloppy way for now.
- $providers = $type->getRouteProviderClasses() ?: [];
- if (empty($providers['moderation'])) {
- $providers['moderation'] = EntityTypeModerationRouteProvider::class;
- $type->setHandlerClass('route_provider', $providers);
- }
-
- return $type;
- }
-
- /**
- * Adds an operation on bundles that should have a Moderation form.
- *
- * @param \Drupal\Core\Entity\EntityInterface $entity
- * The entity on which to define an operation.
- *
- * @return array
- * An array of operation definitions.
- *
- * @see hook_entity_operation()
- */
- public function entityOperation(EntityInterface $entity) {
- $operations = [];
- $type = $entity->getEntityType();
- $bundle_of = $type->getBundleOf();
- if ($this->currentUser->hasPermission('administer content moderation') && $bundle_of &&
- $this->moderationInfo->canModerateEntitiesOfEntityType($this->entityTypeManager->getDefinition($bundle_of))
- ) {
- $operations['manage-moderation'] = [
- 'title' => t('Manage moderation'),
- 'weight' => 27,
- 'url' => Url::fromRoute("entity.{$type->id()}.moderation", [$entity->getEntityTypeId() => $entity->id()]),
- ];
- }
-
- return $operations;
- }
-
- /**
* Gets the "extra fields" for a bundle.
*
* This is a hook bridge.
diff --git a/core/modules/content_moderation/src/Form/BundleModerationConfigurationForm.php b/core/modules/content_moderation/src/Form/BundleModerationConfigurationForm.php
deleted file mode 100644
index 917ec5d..0000000
--- a/core/modules/content_moderation/src/Form/BundleModerationConfigurationForm.php
+++ /dev/null
@@ -1,155 +0,0 @@
-entityTypeManager = $entity_type_manager;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function create(ContainerInterface $container) {
- return new static($container->get('entity_type.manager'));
- }
-
- /**
- * {@inheritdoc}
- *
- * Blank out the base form ID so that form alters that use the base form ID to
- * target both add and edit forms don't pick up this form.
- */
- public function getBaseFormId() {
- return NULL;
- }
-
- /**
- * {@inheritdoc}
- */
- public function form(array $form, FormStateInterface $form_state) {
- /* @var \Drupal\Core\Config\Entity\ConfigEntityInterface $bundle */
- $bundle = $this->getEntity();
- $bundle_of_entity_type = $this->entityTypeManager->getDefinition($bundle->getEntityType()->getBundleOf());
- /* @var \Drupal\workflows\WorkflowInterface[] $workflows */
- $workflows = $this->entityTypeManager->getStorage('workflow')->loadMultiple();
-
- $options = array_map(function (WorkflowInterface $workflow) {
- return $workflow->label();
- }, array_filter($workflows, function (WorkflowInterface $workflow) {
- return $workflow->status() && $workflow->getTypePlugin() instanceof ContentModeration;
- }));
-
- $selected_workflow = array_reduce($workflows, function ($carry, WorkflowInterface $workflow) use ($bundle_of_entity_type, $bundle) {
- $plugin = $workflow->getTypePlugin();
- if ($plugin instanceof ContentModeration && $plugin->appliesToEntityTypeAndBundle($bundle_of_entity_type->id(), $bundle->id())) {
- return $workflow->id();
- }
- return $carry;
- });
- $form['workflow'] = [
- '#type' => 'select',
- '#title' => $this->t('Select the workflow to apply'),
- '#default_value' => $selected_workflow,
- '#options' => $options,
- '#required' => FALSE,
- '#empty_value' => '',
- ];
-
- $form['original_workflow'] = [
- '#type' => 'value',
- '#value' => $selected_workflow,
- ];
-
- $form['bundle'] = [
- '#type' => 'value',
- '#value' => $bundle->id(),
- ];
-
- $form['entity_type'] = [
- '#type' => 'value',
- '#value' => $bundle_of_entity_type->id(),
- ];
-
- // Add a special message when moderation is being disabled.
- if ($selected_workflow) {
- $form['enable_workflow_note'] = [
- '#type' => 'item',
- '#description' => $this->t('After disabling moderation, any existing forward drafts will be accessible via the "Revisions" tab.'),
- '#access' => !empty($selected_workflow)
- ];
- }
-
- return parent::form($form, $form_state);
- }
-
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, FormStateInterface $form_state) {
- // If moderation is enabled, revisions MUST be enabled as well. Otherwise we
- // can't have forward revisions.
- drupal_set_message($this->t('Your settings have been saved.'));
- }
-
- /**
- * {@inheritdoc}
- */
- public function save(array $form, FormStateInterface $form_state) {
- $entity_type_id = $form_state->getValue('entity_type');
- $bundle_id = $form_state->getValue('bundle');
- $new_workflow_id = $form_state->getValue('workflow');
- $original_workflow_id = $form_state->getValue('original_workflow');
- if ($new_workflow_id === $original_workflow_id) {
- // Nothing to do.
- return;
- }
- if ($original_workflow_id) {
- /* @var \Drupal\workflows\WorkflowInterface $workflow */
- $workflow = $this->entityTypeManager->getStorage('workflow')->load($original_workflow_id);
- $workflow->getTypePlugin()->removeEntityTypeAndBundle($entity_type_id, $bundle_id);
- $workflow->save();
- }
- if ($new_workflow_id) {
- /* @var \Drupal\workflows\WorkflowInterface $workflow */
- $workflow = $this->entityTypeManager->getStorage('workflow')->load($new_workflow_id);
- $workflow->getTypePlugin()->addEntityTypeAndBundle($entity_type_id, $bundle_id);
- $workflow->save();
- }
- }
-
- /**
- * {@inheritdoc}
- */
- protected function actions(array $form, FormStateInterface $form_state) {
- $actions['submit'] = [
- '#type' => 'submit',
- '#value' => $this->t('Save'),
- '#submit' => ['::submitForm', '::save'],
- ];
-
- return $actions;
- }
-
-}
diff --git a/core/modules/content_moderation/src/Form/WorkflowTypeEditForm.php b/core/modules/content_moderation/src/Form/WorkflowTypeEditForm.php
new file mode 100644
index 0000000..b32e96a
--- /dev/null
+++ b/core/modules/content_moderation/src/Form/WorkflowTypeEditForm.php
@@ -0,0 +1,191 @@
+get('entity_type.manager'),
+ $container->get('entity_type.bundle.info'),
+ $container->get('content_moderation.moderation_information')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info , ModerationInformationInterface $moderation_information) {
+ $this->entityTypeManager = $entity_type_manager;
+ $this->bundleInfo = $bundle_info;
+ $this->moderationInformation = $moderation_information;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormId() {
+ return 'workflow_type_edit_form';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, FormStateInterface $form_state, WorkflowInterface $workflow = NULL, $entity_type_id = NULL) {
+ $this->workflow = $workflow;
+ try {
+ $this->entityType = $this->entityTypeManager->getDefinition($entity_type_id);
+ }
+ catch (PluginNotFoundException $e) {
+ throw new NotFoundHttpException();
+ }
+
+ $options = $defaults = [];
+ foreach ($this->bundleInfo->getBundleInfo($this->entityType->id()) as $bundle_id => $bundle) {
+ // Check if moderation is enabled for this bundle on any workflow.
+ $moderation_enabled = $this->moderationInformation->shouldModerateEntitiesOfBundle($this->entityType, $bundle_id);
+ // Check if moderation is enabled for this bundle on this workflow.
+ $workflow_moderation_enabled = $this->workflow->getTypePlugin()->appliesToEntityTypeAndBundle($this->entityType->id(), $bundle_id);
+ // Only show bundles that are not enabled anywhere, or enabled on this
+ // workflow.
+ if (!$moderation_enabled || $workflow_moderation_enabled) {
+ // Add the bundle to the options if it's not enabled on a workflow,
+ // unless the workflow it's enabled on is this one.
+ $options[$bundle_id] = ['type' => $bundle['label']];
+ // Add the bundle to the list of default values if it's enabled on this
+ // workflow.
+ $defaults[$bundle_id] = $workflow_moderation_enabled;
+ }
+ }
+
+ if (!empty($options)) {
+ $bundles_header = $this->t('All @entity_type types', ['@entity_type' => $this->entityType->getLabel()]);
+ if ($bundle_entity_type_id = $this->entityType->getBundleEntityType()) {
+ $bundles_header = $this->t('All @entity_type_plural_label', ['@entity_type_plural_label' => $this->entityTypeManager->getDefinition($bundle_entity_type_id)->getPluralLabel()]);
+ }
+ $form['bundles'] = [
+ '#type' => 'tableselect',
+ '#header' => [
+ 'type' => $bundles_header,
+ ],
+ '#options' => $options,
+ '#default_value' => $defaults,
+ ];
+ }
+
+ $form['actions'] = ['#type' => 'actions'];
+ $form['actions']['submit'] = [
+ '#type' => 'submit',
+ '#button_type' => 'primary',
+ '#value' => $this->t('Save'),
+ '#ajax' => [
+ 'callback' => [$this, 'ajaxcallback'],
+ ],
+ ];
+ $form['actions']['cancel'] = [
+ '#type' => 'button',
+ '#value' => $this->t('Cancel'),
+ '#ajax' => [
+ 'callback' => [$this, 'ajaxcallback'],
+ ],
+ ];
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, FormStateInterface $form_state) {
+ foreach ($form_state->getValue('bundles') as $bundle_id => $checked) {
+ if ($checked) {
+ $this->workflow->getTypePlugin()->addEntityTypeAndBundle($this->entityType->id(), $bundle_id);
+ }
+ else {
+ $this->workflow->getTypePlugin()->removeEntityTypeAndBundle($this->entityType->id(), $bundle_id);
+ }
+ }
+ $this->workflow->save();
+ }
+
+ /**
+ * Ajax callback to close the modal and update the selected text.
+ *
+ * @return \Drupal\Core\Ajax\AjaxResponse
+ * An ajax response object.
+ */
+ public function ajaxCallback() {
+ $selected_bundles = [];
+ foreach ($this->bundleInfo->getBundleInfo($this->entityType->id()) as $bundle_id => $bundle) {
+ if ($this->workflow->getTypePlugin()->appliesToEntityTypeAndBundle($this->entityType->id(), $bundle_id)) {
+ $selected_bundles[$bundle_id] = $bundle['label'];
+ }
+ }
+ $response = new AjaxResponse();
+ $response->addCommand(new CloseDialogCommand());
+ $response->addCommand(new HtmlCommand('#selected-' . $this->entityType->id(), !empty($selected_bundles) ? implode(', ', $selected_bundles) : $this->t('none')));
+ return $response;
+ }
+
+ /**
+ * Route title callback.
+ */
+ public function getTitle(WorkflowInterface $workflow = NULL, $entity_type_id) {
+ return $this->t('Select the @entity_type types for the @workflow', ['@entity_type' => $this->entityTypeManager->getDefinition($entity_type_id)->getLabel(), '@workflow' => $workflow->label()]);
+ }
+
+}
diff --git a/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php b/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php
index 7ff1fa5..9f09a9a 100644
--- a/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php
+++ b/core/modules/content_moderation/src/Plugin/Derivative/DynamicLocalTasks.php
@@ -76,19 +76,6 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
public function getDerivativeDefinitions($base_plugin_definition) {
$this->derivatives = [];
- foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
- if ($this->moderationInfo->canModerateEntitiesOfEntityType($entity_type)) {
- $bundle_id = $entity_type->getBundleEntityType();
- $this->derivatives["$bundle_id.moderation_tab"] = [
- 'route_name' => "entity.$bundle_id.moderation",
- 'title' => $this->t('Manage moderation'),
- // @todo - are we sure they all have an edit_form?
- 'base_route' => "entity.$bundle_id.edit_form",
- 'weight' => 30,
- ] + $base_plugin_definition;
- }
- }
-
$latest_version_entities = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $type) {
return $this->moderationInfo->canModerateEntitiesOfEntityType($type) && $type->hasLinkTemplate('latest-version');
});
diff --git a/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
index 31f1c18..b4c918e 100644
--- a/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
+++ b/core/modules/content_moderation/src/Plugin/WorkflowType/ContentModeration.php
@@ -2,14 +2,18 @@
namespace Drupal\content_moderation\Plugin\WorkflowType;
+use Drupal\Component\Serialization\Json;
+use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
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\Core\Url;
+use Drupal\workflows\Plugin\WorkflowTypeFormBase;
use Drupal\workflows\StateInterface;
use Drupal\workflows\WorkflowInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -26,7 +30,7 @@
* },
* )
*/
-class ContentModeration extends WorkflowTypeBase implements ContainerFactoryPluginInterface {
+class ContentModeration extends WorkflowTypeFormBase implements ContainerFactoryPluginInterface {
use StringTranslationTrait;
@@ -38,11 +42,38 @@ class ContentModeration extends WorkflowTypeBase implements ContainerFactoryPlug
protected $entityTypeManager;
/**
- * Creates an instance of the ContentModeration WorkflowType plugin.
+ * The entity type bundle info service.
+ *
+ * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+ */
+ protected $entityTypeBundleInfo;
+
+ /**
+ * The moderation information service.
+ *
+ * @var \Drupal\content_moderation\ModerationInformationInterface
*/
- public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
+ protected $moderationInfo;
+
+ /**
+ * Constructs an ContentModeration object.
+ *
+ * @param array $configuration
+ * A configuration array containing information about the plugin instance.
+ * @param string $plugin_id
+ * The plugin_id for the plugin instance.
+ * @param mixed $plugin_definition
+ * The plugin implementation definition.
+ * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+ * The entity type manager.
+ * @param \Drupal\content_moderation\ModerationInformationInterface $moderation_info
+ * Moderation information service.
+ */
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, ModerationInformationInterface $moderation_info) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
+ $this->entityTypeBundleInfo = $entity_type_bundle_info;
+ $this->moderationInfo = $moderation_info;
}
/**
@@ -53,7 +84,9 @@ public static function create(ContainerInterface $container, array $configuratio
$configuration,
$plugin_id,
$plugin_definition,
- $container->get('entity_type.manager')
+ $container->get('entity_type.manager'),
+ $container->get('entity_type.bundle.info'),
+ $container->get('content_moderation.moderation_information')
);
}
@@ -172,6 +205,9 @@ public function appliesToEntityTypeAndBundle($entity_type_id, $bundle_id) {
* The bundle ID to remove.
*/
public function removeEntityTypeAndBundle($entity_type_id, $bundle_id) {
+ if (!isset($this->configuration['entity_types'][$entity_type_id])) {
+ return;
+ }
$key = array_search($bundle_id, $this->configuration['entity_types'][$entity_type_id], TRUE);
if ($key !== FALSE) {
unset($this->configuration['entity_types'][$entity_type_id][$key]);
@@ -203,7 +239,7 @@ public function addEntityTypeAndBundle($entity_type_id, $bundle_id) {
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function defaultConfiguration() {
// This plugin does not store anything per transition.
@@ -289,4 +325,68 @@ public function getConfiguration() {
return $configuration;
}
+ /**
+ * {@inheritdoc}
+ */
+ public function buildConfigurationForm(array $form, FormStateInterface $form_state, WorkflowInterface $workflow = null) {
+ $header = [
+ 'type' => $this->t('Items'),
+ 'operations' => $this->t('Operations')
+ ];
+ $form['entity_types_container'] = [
+ '#type' => 'details',
+ '#title' => $this->t('This workflow applies to:'),
+ '#open' => TRUE,
+ ];
+ $form['entity_types_container']['entity_types'] = [
+ '#type' => 'table',
+ '#header' => $header,
+ '#empty' => $this->t('There are no entity types.'),
+ ];
+
+ $entity_types = $this->entityTypeManager->getDefinitions();
+ foreach ($entity_types as $entity_type) {
+ if (!$this->moderationInfo->canModerateEntitiesOfEntityType($entity_type)) {
+ continue;
+ }
+
+ $selected_bundles = [];
+ foreach ($this->entityTypeBundleInfo->getBundleInfo($entity_type->id()) as $bundle_id => $bundle) {
+ if ($this->appliesToEntityTypeAndBundle($entity_type->id(), $bundle_id)) {
+ $selected_bundles[$bundle_id] = $bundle['label'];
+ }
+ }
+
+ $form['entity_types_container']['entity_types'][$entity_type->id()] = [
+ 'type' => [
+ 'label' => ['#markup' => '' . $this->t('%bundle types', ['%bundle' => $entity_type->getLabel()]) . ''],
+ 'selected' => [
+ '#prefix' => '
',
+ '#markup' => !empty($selected_bundles) ? implode(', ', $selected_bundles) : $this->t('none'),
+ '#suffix' => '',
+ ],
+ ],
+ 'operations' => [
+ '#type' => 'operations',
+ '#links' => [
+ 'Add' => [
+ 'title' => $this->t('Select'),
+ 'url' => Url::fromRoute('workflow.type_edit_form', ['workflow' => $workflow->id(), 'entity_type_id' => $entity_type->id()]),
+ 'attributes' => [
+ 'aria-label' => $this->t('Select'),
+ 'class' => ['use-ajax'],
+ 'data-dialog-type' => 'modal',
+ 'data-dialog-options' => Json::encode([
+ 'width' => 700,
+ ]),
+ ],
+ ],
+ ],
+ ],
+ ];
+ }
+
+ return $form;
+ }
+
}
diff --git a/core/modules/content_moderation/src/Routing/EntityTypeModerationRouteProvider.php b/core/modules/content_moderation/src/Routing/EntityTypeModerationRouteProvider.php
deleted file mode 100644
index d1dcd2b..0000000
--- a/core/modules/content_moderation/src/Routing/EntityTypeModerationRouteProvider.php
+++ /dev/null
@@ -1,59 +0,0 @@
-getModerationFormRoute($entity_type)) {
- $entity_type_id = $entity_type->id();
- $collection->add("entity.{$entity_type_id}.moderation", $moderation_route);
- }
-
- return $collection;
- }
-
- /**
- * Gets the moderation-form route.
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * The entity type.
- *
- * @return \Symfony\Component\Routing\Route|null
- * The generated route, if available.
- */
- protected function getModerationFormRoute(EntityTypeInterface $entity_type) {
- if ($entity_type->hasLinkTemplate('moderation-form') && $entity_type->getFormClass('moderation')) {
- $entity_type_id = $entity_type->id();
-
- $route = new Route($entity_type->getLinkTemplate('moderation-form'));
-
- // @todo Come up with a new permission.
- $route
- ->setDefaults([
- '_entity_form' => "{$entity_type_id}.moderation",
- '_title' => 'Moderation',
- ])
- ->setRequirement('_permission', 'administer content moderation')
- ->setOption('parameters', [
- $entity_type_id => ['type' => 'entity:' . $entity_type_id],
- ]);
-
- return $route;
- }
- }
-
-}
diff --git a/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php b/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php
index 593a9f9..d2ff836 100644
--- a/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php
+++ b/core/modules/content_moderation/src/Tests/ModerationStateBlockTest.php
@@ -51,17 +51,9 @@ protected function setUp() {
public function testCustomBlockModeration() {
$this->drupalLogin($this->rootUser);
- $this->drupalGet('admin/structure/block/block-content/types');
- $this->assertLinkByHref('admin/structure/block/block-content/manage/basic/moderation');
- $this->drupalGet('admin/structure/block/block-content/manage/basic');
- $this->assertLinkByHref('admin/structure/block/block-content/manage/basic/moderation');
- $this->drupalGet('admin/structure/block/block-content/manage/basic/moderation');
-
- // Enable moderation for custom blocks at
- // admin/structure/block/block-content/manage/basic/moderation.
- $edit = ['workflow' => 'editorial'];
- $this->drupalPostForm(NULL, $edit, t('Save'));
- $this->assertText(t('Your settings have been saved.'));
+ // Enable moderation for custom blocks.
+ $edit['bundles[basic]'] = TRUE;
+ $this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/block_content', $edit, t('Save'));
// Create a custom block at block/add and save it as draft.
$body = 'Body of moderated block';
diff --git a/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php b/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php
index 49eee6d..2525331 100644
--- a/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php
+++ b/core/modules/content_moderation/src/Tests/ModerationStateNodeTest.php
@@ -52,9 +52,8 @@ public function testCreatingContent() {
$this->assertText(t('The Moderated content moderated content has been deleted.'));
// Disable content moderation.
- $this->drupalPostForm('admin/structure/types/manage/moderated_content/moderation', ['workflow' => ''], t('Save'));
- $this->drupalGet('admin/structure/types/manage/moderated_content/moderation');
- $this->assertOptionSelected('edit-workflow', '');
+ $edit['bundles[moderated_content]'] = FALSE;
+ $this->drupalPostForm('admin/config/workflow/workflows/manage/editorial/type/node', $edit, t('Save'));;
// Ensure the parent environment is up-to-date.
// @see content_moderation_workflow_insert()
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
diff --git a/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php b/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php
index 1911d9f..849713d 100644
--- a/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php
+++ b/core/modules/content_moderation/src/Tests/ModerationStateNodeTypeTest.php
@@ -56,17 +56,8 @@ public function testEnablingOnExistingContent() {
], t('Save and publish'));
$this->assertText('Not moderated Test has been created.');
- // Now enable moderation state, ensuring all the expected links and tabs are
- // present.
- $this->drupalGet('admin/structure/types');
- $this->assertLinkByHref('admin/structure/types/manage/not_moderated/moderation');
- $this->drupalGet('admin/structure/types/manage/not_moderated');
- $this->assertLinkByHref('admin/structure/types/manage/not_moderated/moderation');
- $this->drupalGet('admin/structure/types/manage/not_moderated/moderation');
- $this->assertOptionSelected('edit-workflow', '');
- $this->assertNoLink('Delete');
- $edit['workflow'] = 'editorial';
- $this->drupalPostForm(NULL, $edit, t('Save'));
+ // Now enable moderation state.
+ $this->enableModerationThroughUi('not_moderated');
// And make sure it works.
$nodes = \Drupal::entityTypeManager()->getStorage('node')
diff --git a/core/modules/content_moderation/src/Tests/ModerationStateTestBase.php b/core/modules/content_moderation/src/Tests/ModerationStateTestBase.php
index 8574a99..e8fbc5b 100644
--- a/core/modules/content_moderation/src/Tests/ModerationStateTestBase.php
+++ b/core/modules/content_moderation/src/Tests/ModerationStateTestBase.php
@@ -41,6 +41,7 @@
'access content overview',
'use editorial transition create_new_draft',
'use editorial transition publish',
+ 'administer workflows',
];
/**
@@ -115,9 +116,13 @@ protected function createContentTypeFromUi($content_type_name, $content_type_id,
* @param string $workflow_id
* The workflow to attach to the bundle.
*/
- protected function enableModerationThroughUi($content_type_id, $workflow_id = 'editorial') {
- $edit['workflow'] = $workflow_id;
- $this->drupalPostForm('admin/structure/types/manage/' . $content_type_id . '/moderation', $edit, t('Save'));
+ public function enableModerationThroughUi($content_type_id, $workflow_id = 'editorial') {
+ $this->drupalGet('/admin/config/workflow/workflows');
+ $this->assertLinkByHref('admin/config/workflow/workflows/manage/' . $workflow_id);
+ $this->drupalGet('/admin/config/workflow/workflows/manage/' . $workflow_id);
+ $this->assertText('Content');
+ $edit['bundles[' . $content_type_id . ']'] = TRUE;
+ $this->drupalPostForm('admin/config/workflow/workflows/manage/' . $workflow_id . '/type/node', $edit, t('Save'));
// Ensure the parent environment is up-to-date.
// @see content_moderation_workflow_insert()
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
diff --git a/core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php b/core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php
index 1319eca..4c7cc6e 100644
--- a/core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php
+++ b/core/modules/content_moderation/tests/src/Functional/ModerationStateTestBase.php
@@ -29,6 +29,7 @@
* @var array
*/
protected $permissions = [
+ 'administer workflows',
'administer content moderation',
'access administration pages',
'administer content types',
@@ -112,9 +113,11 @@ protected function createContentTypeFromUi($content_type_name, $content_type_id,
* @param string $workflow_id
* The workflow to attach to the bundle.
*/
- protected function enableModerationThroughUi($content_type_id, $workflow_id = 'editorial') {
- $edit['workflow'] = $workflow_id;
- $this->drupalPostForm('admin/structure/types/manage/' . $content_type_id . '/moderation', $edit, t('Save'));
+ public function enableModerationThroughUi($content_type_id, $workflow_id = 'editorial') {
+ $this->drupalGet('/admin/config/workflow/workflows');
+ $this->assertLinkByHref('admin/config/workflow/workflows/manage/' . $workflow_id);
+ $edit['bundles[' . $content_type_id . ']'] = TRUE;
+ $this->drupalPostForm('admin/config/workflow/workflows/manage/' . $workflow_id . '/type/node', $edit, t('Save'));
// Ensure the parent environment is up-to-date.
// @see content_moderation_workflow_insert()
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php
index c2ea8c5..220ac5d 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowTypeApiTest.php
@@ -101,4 +101,26 @@ public function testAddEntityTypeAndBundle() {
);
}
+ /**
+ * @covers ::addEntityTypeAndBundle
+ * @covers ::removeEntityTypeAndBundle
+ */
+ public function testRemoveEntityTypeAndBundle() {
+ /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration $workflow_plugin */
+ $workflow_plugin = $this->workflow->getTypePlugin();
+
+ // There should be no bundles for fake_node to start with.
+ $this->assertEquals([], $workflow_plugin->getBundlesForEntityType('fake_node'));
+ // Removing a bundle which is not set on the workflow should not throw an
+ // error and should still result in none being returned.
+ $workflow_plugin->removeEntityTypeAndBundle('fake_node', 'fake_page');
+ $this->assertEquals([], $workflow_plugin->getBundlesForEntityType('fake_node'));
+ // Adding a bundle for fake_node should result it in being returned, but
+ // then removing it will return no bundles for fake_node.
+ $workflow_plugin->addEntityTypeAndBundle('fake_node', 'fake_page');
+ $this->assertEquals(['fake_page'], $workflow_plugin->getBundlesForEntityType('fake_node'));
+ $workflow_plugin->removeEntityTypeAndBundle('fake_node', 'fake_page');
+ $this->assertEquals([], $workflow_plugin->getBundlesForEntityType('fake_node'));
+ }
+
}
diff --git a/core/modules/content_moderation/tests/src/Kernel/EntityTypeInfoTest.php b/core/modules/content_moderation/tests/src/Kernel/EntityTypeInfoTest.php
index 1c45721..a5791c8 100644
--- a/core/modules/content_moderation/tests/src/Kernel/EntityTypeInfoTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/EntityTypeInfoTest.php
@@ -20,6 +20,7 @@ class EntityTypeInfoTest extends KernelTestBase {
*/
public static $modules = [
'content_moderation',
+ 'workflows',
'entity_test',
];
diff --git a/core/modules/workflows/src/Form/WorkflowEditForm.php b/core/modules/workflows/src/Form/WorkflowEditForm.php
index c0ea5a4..764c0c9 100644
--- a/core/modules/workflows/src/Form/WorkflowEditForm.php
+++ b/core/modules/workflows/src/Form/WorkflowEditForm.php
@@ -2,6 +2,8 @@
namespace Drupal\workflows\Form;
+use Drupal\Core\Form\SubformState;
+use Drupal\workflows\WorkflowTypeFormInterface;
use Drupal\workflows\Entity\Workflow;
use Drupal\workflows\State;
use Drupal\Core\Entity\EntityForm;
@@ -180,16 +182,41 @@ public function form(array $form, FormStateInterface $form_state) {
'#markup' => $workflow->toLink($this->t('Add a new transition'), 'add-transition-form')->toString(),
];
+ if ($workflow->getTypePlugin() instanceof WorkflowTypeFormInterface) {
+ $form['type_settings'] = [
+ '#tree' => TRUE,
+ ];
+ $subform_state = SubformState::createForSubform($form['type_settings'], $form, $form_state);
+ $form['type_settings'] += $workflow->getTypePlugin()->buildConfigurationForm($form['type_settings'], $subform_state, $workflow);
+ }
+
return $form;
}
/**
* {@inheritdoc}
*/
+ public function validateForm(array &$form, FormStateInterface $form_state) {
+ /* @var \Drupal\workflows\WorkflowInterface $workflow */
+ $workflow = $this->entity;
+ if ($workflow->getTypePlugin() instanceof WorkflowTypeFormInterface) {
+ $subform_state = SubformState::createForSubform($form['type_settings'], $form, $form_state);
+ $workflow->getTypePlugin()->validateConfigurationForm($form['type_settings'], $subform_state);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function save(array $form, FormStateInterface $form_state) {
/* @var \Drupal\workflows\WorkflowInterface $workflow */
$workflow = $this->entity;
+ if ($workflow->getTypePlugin() instanceof WorkflowTypeFormInterface) {
+ $subform_state = SubformState::createForSubform($form['type_settings'], $form, $form_state);
+ $workflow->getTypePlugin()->submitConfigurationForm($form['type_settings'], $subform_state);
+ }
$workflow->save();
+
drupal_set_message($this->t('Saved the %label Workflow.', ['%label' => $workflow->label()]));
}
diff --git a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
index 59c6b96..7e9fed5 100644
--- a/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
+++ b/core/modules/workflows/src/Plugin/WorkflowTypeBase.php
@@ -56,28 +56,28 @@ public function checkWorkflowAccess(WorkflowInterface $entity, $operation, Accou
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function decorateState(StateInterface $state) {
return $state;
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function deleteState($state_id) {
unset($this->configuration['states'][$state_id]);
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function decorateTransition(TransitionInterface $transition) {
return $transition;
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function deleteTransition($transition_id) {
unset($this->configuration['transitions'][$transition_id]);
@@ -98,14 +98,14 @@ public function buildTransitionConfigurationForm(FormStateInterface $form_state,
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getConfiguration() {
return $this->configuration;
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = NestedArray::mergeDeep(
@@ -122,7 +122,7 @@ public function getRequiredStates() {
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function defaultConfiguration() {
return [
@@ -132,7 +132,7 @@ public function defaultConfiguration() {
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function calculateDependencies() {
return [];
diff --git a/core/modules/workflows/src/Plugin/WorkflowTypeFormBase.php b/core/modules/workflows/src/Plugin/WorkflowTypeFormBase.php
new file mode 100644
index 0000000..942c2d6
--- /dev/null
+++ b/core/modules/workflows/src/Plugin/WorkflowTypeFormBase.php
@@ -0,0 +1,30 @@
+ '',
+ ];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+ $form['example_setting'] = [
+ '#type' => 'textfield',
+ '#title' => $this->t('Example global workflow setting'),
+ '#description' => $this->t('Extra information added to the workflow'),
+ '#default_value' => $this->configuration['example_setting'],
+ ];
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
+ $this->configuration['example_setting'] = $form_state->getValue('example_setting');
+ }
+
}
diff --git a/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php b/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
index 3014dd7..f42edfd 100644
--- a/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
+++ b/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
@@ -251,6 +251,28 @@ public function testWorkflowCreation() {
}
/**
+ * Test the workflow configuration form.
+ */
+ public function testWorkflowConfigurationForm() {
+ $workflow = Workflow::create(['id' => 'test', 'type' => 'workflow_type_complex_test', 'label' => 'Test']);
+ $workflow
+ ->addState('published', 'Published')
+ ->addTransition('publish', 'Publish', ['published'], 'published')
+ ->save();
+
+ $this->drupalLogin($this->createUser(['administer workflows']));
+
+ // Add additional information to the workflow via the configuration form.
+ $this->drupalGet('admin/config/workflow/workflows/manage/test');
+ $this->assertSession()->pageTextContains('Example global workflow setting');
+ $this->submitForm(['type_settings[example_setting]' => 'Extra global settings'], 'Save');
+
+ $workflow_storage = $this->container->get('entity_type.manager')->getStorage('workflow');
+ $workflow = $workflow_storage->loadUnchanged('test');
+ $this->assertEquals('Extra global settings', $workflow->getTypePlugin()->getConfiguration()['example_setting']);
+ }
+
+ /**
* Tests that workflow types can add form fields to states and transitions.
*/
public function testWorkflowDecoration() {