entityTypeManager = $entity_type_manager; $this->entityTypeBundleInfo = $entity_type_bundle_info; $this->moderationInfo = $moderation_info; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('entity_type.bundle.info'), $container->get('content_moderation.moderation_information') ); } /** * {@inheritdoc} */ public function checkWorkflowAccess(WorkflowInterface $entity, $operation, AccountInterface $account) { if ($operation === 'view') { return AccessResult::allowedIfHasPermission($account, 'view content moderation'); } return parent::checkWorkflowAccess($entity, $operation, $account); } /** * {@inheritdoc} */ public function decorateState(StateInterface $state) { if (isset($this->configuration['states'][$state->id()]['published']) && isset($this->configuration['states'][$state->id()]['default_revision'])) { $state = new ContentModerationState($state, $this->configuration['states'][$state->id()]['published'], $this->configuration['states'][$state->id()]['default_revision']); } else { $state = new ContentModerationState($state); } return $state; } /** * {@inheritdoc} */ public function workflowHasData(WorkflowInterface $workflow) { return (bool) $this->entityTypeManager ->getStorage('content_moderation_state') ->getQuery() ->condition('workflow', $workflow->id()) ->count() ->accessCheck(FALSE) ->range(0, 1) ->execute(); } /** * {@inheritdoc} */ public function workflowStateHasData(WorkflowInterface $workflow, StateInterface $state) { return (bool) $this->entityTypeManager ->getStorage('content_moderation_state') ->getQuery() ->condition('workflow', $workflow->id()) ->condition('moderation_state', $state->id()) ->count() ->accessCheck(FALSE) ->range(0, 1) ->execute(); } /** * {@inheritdoc} */ public function buildStateConfigurationForm(FormStateInterface $form_state, WorkflowInterface $workflow, StateInterface $state = NULL) { /** @var \Drupal\content_moderation\ContentModerationState $state */ $is_required_state = isset($state) ? in_array($state->id(), $this->getRequiredStates(), TRUE) : FALSE; $form = []; $form['published'] = [ '#type' => 'checkbox', '#title' => $this->t('Published'), '#description' => $this->t('When content reaches this state it should be published.'), '#default_value' => isset($state) ? $state->isPublishedState() : FALSE, '#disabled' => $is_required_state, ]; $form['default_revision'] = [ '#type' => 'checkbox', '#title' => $this->t('Default revision'), '#description' => $this->t('When content reaches this state it should be made the default revision; this is implied for published states.'), '#default_value' => isset($state) ? $state->isDefaultRevisionState() : FALSE, '#disabled' => $is_required_state, // @todo Add form #state to force "make default" on when "published" is // on for a state. // @see https://www.drupal.org/node/2645614 ]; return $form; } /** * Gets the entity types the workflow is applied to. * * @return string[] * The entity types the workflow is applied to. */ public function getEntityTypes() { return array_keys($this->configuration['entity_types']); } /** * Gets any bundles the workflow is applied to for the given entity type. * * @param string $entity_type_id * The entity type ID to get the bundles for. * * @return string[] * The bundles of the entity type the workflow is applied to or an empty * array if the entity type is not applied to the workflow. */ public function getBundlesForEntityType($entity_type_id) { return isset($this->configuration['entity_types'][$entity_type_id]) ? $this->configuration['entity_types'][$entity_type_id] : []; } /** * Checks if the workflow applies to the supplied entity type and bundle. * * @param string $entity_type_id * The entity type ID to check. * @param string $bundle_id * The bundle ID to check. * * @return bool * TRUE if the workflow applies to the supplied entity type ID and bundle * ID. FALSE if not. */ public function appliesToEntityTypeAndBundle($entity_type_id, $bundle_id) { return in_array($bundle_id, $this->getBundlesForEntityType($entity_type_id), TRUE); } /** * Removes an entity type ID / bundle ID from the workflow. * * @param string $entity_type_id * The entity type ID to remove. * @param string $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]); if (empty($this->configuration['entity_types'][$entity_type_id])) { unset($this->configuration['entity_types'][$entity_type_id]); } else { $this->configuration['entity_types'][$entity_type_id] = array_values($this->configuration['entity_types'][$entity_type_id]); } } } /** * Add an entity type ID / bundle ID to the workflow. * * @param string $entity_type_id * The entity type ID to add. It is responsibility of the caller to provide * a valid entity type ID. * @param string $bundle_id * The bundle ID to add. It is responsibility of the caller to provide a * valid bundle ID. */ public function addEntityTypeAndBundle($entity_type_id, $bundle_id) { if (!$this->appliesToEntityTypeAndBundle($entity_type_id, $bundle_id)) { $this->configuration['entity_types'][$entity_type_id][] = $bundle_id; sort($this->configuration['entity_types'][$entity_type_id]); ksort($this->configuration['entity_types']); } } /** * {@inheritdoc} */ public function defaultConfiguration() { 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' => [], ]; } /** * {@inheritdoc} */ public function calculateDependencies() { $dependencies = parent::calculateDependencies(); foreach ($this->getEntityTypes() as $entity_type_id) { $entity_definition = $this->entityTypeManager->getDefinition($entity_type_id); foreach ($this->getBundlesForEntityType($entity_type_id) as $bundle) { $dependency = $entity_definition->getBundleConfigDependency($bundle); $dependencies[$dependency['type']][] = $dependency['name']; } } return $dependencies; } /** * {@inheritdoc} */ public function onDependencyRemoval(array $dependencies) { $changed = parent::onDependencyRemoval($dependencies); // When bundle config entities are removed, ensure they are cleaned up from // the workflow. foreach ($dependencies['config'] as $removed_config) { if ($entity_type_id = $removed_config->getEntityType()->getBundleOf()) { $bundle_id = $removed_config->id(); $this->removeEntityTypeAndBundle($entity_type_id, $bundle_id); $changed = TRUE; } } // When modules that provide entity types are removed, ensure they are also // removed from the workflow. if (!empty($dependencies['module'])) { // Gather all entity definitions provided by the dependent modules which // are being removed. $module_entity_definitions = []; foreach ($this->entityTypeManager->getDefinitions() as $entity_definition) { if (in_array($entity_definition->getProvider(), $dependencies['module'])) { $module_entity_definitions[] = $entity_definition; } } // For all entity types provided by the uninstalled modules, remove any // configuration for those types. foreach ($module_entity_definitions as $module_entity_definition) { foreach ($this->getBundlesForEntityType($module_entity_definition->id()) as $bundle) { $this->removeEntityTypeAndBundle($module_entity_definition->id(), $bundle); $changed = TRUE; } } } return $changed; } /** * {@inheritdoc} */ public function getConfiguration() { $configuration = parent::getConfiguration(); // Ensure that states and entity types are ordered consistently. ksort($configuration['states']); ksort($configuration['entity_types']); return $configuration; } /** * {@inheritdoc} */ public function getInitialState(WorkflowInterface $workflow, $entity = NULL) { if ($entity instanceof EntityPublishedInterface) { return $workflow->getState($entity->isPublished() && !$entity->isNew() ? 'published' : 'draft'); } return parent::getInitialState($workflow); } /** * {@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' => [ 'select' => [ 'title' => $this->t('Select'), 'url' => Url::fromRoute('content_moderation.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; } }