3 namespace Drupal\content_moderation\Plugin\WorkflowType;
5 use Drupal\content_moderation\ModerationInformationInterface;
6 use Drupal\Core\Entity\ContentEntityInterface;
7 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
8 use Drupal\Core\Entity\EntityTypeManagerInterface;
9 use Drupal\Core\Entity\EntityPublishedInterface;
10 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
11 use Drupal\Core\StringTranslation\StringTranslationTrait;
12 use Drupal\content_moderation\ContentModerationState;
13 use Drupal\workflows\Plugin\WorkflowTypeBase;
14 use Drupal\workflows\StateInterface;
15 use Drupal\workflows\WorkflowInterface;
16 use Symfony\Component\DependencyInjection\ContainerInterface;
19 * Attaches workflows to content entity types and their bundles.
22 * id = "content_moderation",
23 * label = @Translation("Content moderation"),
29 * "configure" = "\Drupal\content_moderation\Form\ContentModerationConfigureForm",
30 * "state" = "\Drupal\content_moderation\Form\ContentModerationStateForm"
34 class ContentModeration extends WorkflowTypeBase implements ContentModerationInterface, ContainerFactoryPluginInterface {
36 use StringTranslationTrait;
39 * The entity type manager.
41 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
43 protected $entityTypeManager;
46 * The entity type bundle info service.
48 * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
50 protected $entityTypeBundleInfo;
53 * The moderation information service.
55 * @var \Drupal\content_moderation\ModerationInformationInterface
57 protected $moderationInfo;
60 * Constructs a ContentModeration object.
62 * @param array $configuration
63 * A configuration array containing information about the plugin instance.
64 * @param string $plugin_id
65 * The plugin_id for the plugin instance.
66 * @param mixed $plugin_definition
67 * The plugin implementation definition.
68 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
69 * The entity type manager.
70 * @param \Drupal\content_moderation\ModerationInformationInterface $moderation_info
71 * Moderation information service.
73 public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, ModerationInformationInterface $moderation_info) {
74 parent::__construct($configuration, $plugin_id, $plugin_definition);
75 $this->entityTypeManager = $entity_type_manager;
76 $this->entityTypeBundleInfo = $entity_type_bundle_info;
77 $this->moderationInfo = $moderation_info;
83 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
88 $container->get('entity_type.manager'),
89 $container->get('entity_type.bundle.info'),
90 $container->get('content_moderation.moderation_information')
97 public function getState($state_id) {
98 $state = parent::getState($state_id);
99 if (isset($this->configuration['states'][$state->id()]['published']) && isset($this->configuration['states'][$state->id()]['default_revision'])) {
100 $state = new ContentModerationState($state, $this->configuration['states'][$state->id()]['published'], $this->configuration['states'][$state->id()]['default_revision']);
103 $state = new ContentModerationState($state);
111 public function workflowHasData(WorkflowInterface $workflow) {
112 return (bool) $this->entityTypeManager
113 ->getStorage('content_moderation_state')
115 ->condition('workflow', $workflow->id())
125 public function workflowStateHasData(WorkflowInterface $workflow, StateInterface $state) {
126 return (bool) $this->entityTypeManager
127 ->getStorage('content_moderation_state')
129 ->condition('workflow', $workflow->id())
130 ->condition('moderation_state', $state->id())
140 public function getEntityTypes() {
141 return array_keys($this->configuration['entity_types']);
147 public function getBundlesForEntityType($entity_type_id) {
148 return isset($this->configuration['entity_types'][$entity_type_id]) ? $this->configuration['entity_types'][$entity_type_id] : [];
154 public function appliesToEntityTypeAndBundle($entity_type_id, $bundle_id) {
155 return in_array($bundle_id, $this->getBundlesForEntityType($entity_type_id), TRUE);
161 public function removeEntityTypeAndBundle($entity_type_id, $bundle_id) {
162 if (!isset($this->configuration['entity_types'][$entity_type_id])) {
165 $key = array_search($bundle_id, $this->configuration['entity_types'][$entity_type_id], TRUE);
166 if ($key !== FALSE) {
167 unset($this->configuration['entity_types'][$entity_type_id][$key]);
168 if (empty($this->configuration['entity_types'][$entity_type_id])) {
169 unset($this->configuration['entity_types'][$entity_type_id]);
172 $this->configuration['entity_types'][$entity_type_id] = array_values($this->configuration['entity_types'][$entity_type_id]);
180 public function addEntityTypeAndBundle($entity_type_id, $bundle_id) {
181 if (!$this->appliesToEntityTypeAndBundle($entity_type_id, $bundle_id)) {
182 $this->configuration['entity_types'][$entity_type_id][] = $bundle_id;
183 sort($this->configuration['entity_types'][$entity_type_id]);
184 ksort($this->configuration['entity_types']);
191 public function defaultConfiguration() {
196 'published' => FALSE,
197 'default_revision' => FALSE,
201 'label' => 'Published',
203 'default_revision' => TRUE,
208 'create_new_draft' => [
209 'label' => 'Create New Draft',
218 'label' => 'Publish',
227 'entity_types' => [],
234 public function calculateDependencies() {
235 $dependencies = parent::calculateDependencies();
236 foreach ($this->getEntityTypes() as $entity_type_id) {
237 $entity_definition = $this->entityTypeManager->getDefinition($entity_type_id);
238 foreach ($this->getBundlesForEntityType($entity_type_id) as $bundle) {
239 $dependency = $entity_definition->getBundleConfigDependency($bundle);
240 $dependencies[$dependency['type']][] = $dependency['name'];
243 return $dependencies;
249 public function onDependencyRemoval(array $dependencies) {
250 $changed = parent::onDependencyRemoval($dependencies);
252 // When bundle config entities are removed, ensure they are cleaned up from
254 foreach ($dependencies['config'] as $removed_config) {
255 if ($entity_type_id = $removed_config->getEntityType()->getBundleOf()) {
256 $bundle_id = $removed_config->id();
257 $this->removeEntityTypeAndBundle($entity_type_id, $bundle_id);
262 // When modules that provide entity types are removed, ensure they are also
263 // removed from the workflow.
264 if (!empty($dependencies['module'])) {
265 // Gather all entity definitions provided by the dependent modules which
266 // are being removed.
267 $module_entity_definitions = [];
268 foreach ($this->entityTypeManager->getDefinitions() as $entity_definition) {
269 if (in_array($entity_definition->getProvider(), $dependencies['module'])) {
270 $module_entity_definitions[] = $entity_definition;
274 // For all entity types provided by the uninstalled modules, remove any
275 // configuration for those types.
276 foreach ($module_entity_definitions as $module_entity_definition) {
277 foreach ($this->getBundlesForEntityType($module_entity_definition->id()) as $bundle) {
278 $this->removeEntityTypeAndBundle($module_entity_definition->id(), $bundle);
290 public function getConfiguration() {
291 $configuration = parent::getConfiguration();
292 // Ensure that states and entity types are ordered consistently.
293 ksort($configuration['states']);
294 ksort($configuration['entity_types']);
295 return $configuration;
301 public function getInitialState($entity = NULL) {
302 // Workflows are not tied to entities, but Content Moderation adds the
303 // relationship between Workflows and entities. Content Moderation needs the
304 // entity object to be able to determine the initial state based on
305 // publishing status.
306 if (!($entity instanceof ContentEntityInterface)) {
307 throw new \InvalidArgumentException('A content entity object must be supplied.');
309 if ($entity instanceof EntityPublishedInterface) {
310 return $this->getState($entity->isPublished() && !$entity->isNew() ? 'published' : 'draft');
312 // Workflows determines the initial state for non-publishable entities.
313 return parent::getInitialState();