b5263639e2f76d97c75d7b0ebeaa5b64ed902eb3
[yaffs-website] / web / core / modules / content_moderation / src / Plugin / Field / ModerationStateFieldItemList.php
1 <?php
2
3 namespace Drupal\content_moderation\Plugin\Field;
4
5 use Drupal\Core\Entity\ContentEntityInterface;
6 use Drupal\Core\Entity\EntityPublishedInterface;
7 use Drupal\Core\Field\FieldItemList;
8
9 /**
10  * A computed field that provides a content entity's moderation state.
11  *
12  * It links content entities to a moderation state configuration entity via a
13  * moderation state content entity.
14  */
15 class ModerationStateFieldItemList extends FieldItemList {
16
17   /**
18    * Gets the moderation state ID linked to a content entity revision.
19    *
20    * @return string|null
21    *   The moderation state ID linked to a content entity revision.
22    */
23   protected function getModerationStateId() {
24     $entity = $this->getEntity();
25
26     /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
27     $moderation_info = \Drupal::service('content_moderation.moderation_information');
28     if (!$moderation_info->shouldModerateEntitiesOfBundle($entity->getEntityType(), $entity->bundle())) {
29       return NULL;
30     }
31
32     // Existing entities will have a corresponding content_moderation_state
33     // entity associated with them.
34     if (!$entity->isNew() && $content_moderation_state = $this->loadContentModerationStateRevision($entity)) {
35       return $content_moderation_state->moderation_state->value;
36     }
37
38     // It is possible that the bundle does not exist at this point. For example,
39     // the node type form creates a fake Node entity to get default values.
40     // @see \Drupal\node\NodeTypeForm::form()
41     $workflow = $moderation_info->getWorkFlowForEntity($entity);
42     return $workflow ? $workflow->getTypePlugin()->getInitialState($entity)->id() : NULL;
43   }
44
45   /**
46    * Load the content moderation state revision associated with an entity.
47    *
48    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
49    *   The entity the content moderation state entity will be loaded from.
50    *
51    * @return \Drupal\content_moderation\Entity\ContentModerationStateInterface|null
52    *   The content_moderation_state revision or FALSE if none exists.
53    */
54   protected function loadContentModerationStateRevision(ContentEntityInterface $entity) {
55     $moderation_info = \Drupal::service('content_moderation.moderation_information');
56     $content_moderation_storage = \Drupal::entityTypeManager()->getStorage('content_moderation_state');
57
58     $revisions = \Drupal::service('entity.query')->get('content_moderation_state')
59       ->condition('content_entity_type_id', $entity->getEntityTypeId())
60       ->condition('content_entity_id', $entity->id())
61       // Ensure the correct revision is loaded in scenarios where a revision is
62       // being reverted.
63       ->condition('content_entity_revision_id', $entity->isNewRevision() ? $entity->getLoadedRevisionId() : $entity->getRevisionId())
64       ->condition('workflow', $moderation_info->getWorkflowForEntity($entity)->id())
65       ->allRevisions()
66       ->sort('revision_id', 'DESC')
67       ->execute();
68     if (empty($revisions)) {
69       return NULL;
70     }
71
72     /** @var \Drupal\content_moderation\Entity\ContentModerationStateInterface $content_moderation_state */
73     $content_moderation_state = $content_moderation_storage->loadRevision(key($revisions));
74     if ($entity->getEntityType()->hasKey('langcode')) {
75       $langcode = $entity->language()->getId();
76       if (!$content_moderation_state->hasTranslation($langcode)) {
77         $content_moderation_state->addTranslation($langcode);
78       }
79       if ($content_moderation_state->language()->getId() !== $langcode) {
80         $content_moderation_state = $content_moderation_state->getTranslation($langcode);
81       }
82     }
83     return $content_moderation_state;
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   public function get($index) {
90     if ($index !== 0) {
91       throw new \InvalidArgumentException('An entity can not have multiple moderation states at the same time.');
92     }
93     $this->computeModerationFieldItemList();
94     return isset($this->list[$index]) ? $this->list[$index] : NULL;
95   }
96
97   /**
98    * {@inheritdoc}
99    */
100   public function getIterator() {
101     $this->computeModerationFieldItemList();
102     return parent::getIterator();
103   }
104
105   /**
106    * Recalculate the moderation field item list.
107    */
108   protected function computeModerationFieldItemList() {
109     // Compute the value of the moderation state.
110     $index = 0;
111     if (!isset($this->list[$index]) || $this->list[$index]->isEmpty()) {
112
113       $moderation_state = $this->getModerationStateId();
114       // Do not store NULL values in the static cache.
115       if ($moderation_state) {
116         $this->list[$index] = $this->createItem($index, $moderation_state);
117       }
118     }
119   }
120
121   /**
122    * {@inheritdoc}
123    */
124   public function onChange($delta) {
125     $this->updateModeratedEntity($this->list[$delta]->value);
126
127     parent::onChange($delta);
128   }
129
130   /**
131    * {@inheritdoc}
132    */
133   public function setValue($values, $notify = TRUE) {
134     parent::setValue($values, $notify);
135
136     if (isset($this->list[0])) {
137       $this->updateModeratedEntity($this->list[0]->value);
138     }
139   }
140
141   /**
142    * Updates the default revision flag and the publishing status of the entity.
143    *
144    * @param string $moderation_state_id
145    *   The ID of the new moderation state.
146    */
147   protected function updateModeratedEntity($moderation_state_id) {
148     $entity = $this->getEntity();
149
150     /** @var \Drupal\content_moderation\ModerationInformationInterface $content_moderation_info */
151     $content_moderation_info = \Drupal::service('content_moderation.moderation_information');
152     $workflow = $content_moderation_info->getWorkflowForEntity($entity);
153
154     // Change the entity's default revision flag and the publishing status only
155     // if the new workflow state is a valid one.
156     if ($workflow && $workflow->getTypePlugin()->hasState($moderation_state_id)) {
157       /** @var \Drupal\content_moderation\ContentModerationState $current_state */
158       $current_state = $workflow->getTypePlugin()->getState($moderation_state_id);
159
160       // This entity is default if it is new, a new translation, the default
161       // revision state, or the default revision is not published.
162       $update_default_revision = $entity->isNew()
163         || $entity->isNewTranslation()
164         || $current_state->isDefaultRevisionState()
165         || !$content_moderation_info->isDefaultRevisionPublished($entity);
166
167       $entity->isDefaultRevision($update_default_revision);
168
169       // Update publishing status if it can be updated and if it needs updating.
170       $published_state = $current_state->isPublishedState();
171       if (($entity instanceof EntityPublishedInterface) && $entity->isPublished() !== $published_state) {
172         $published_state ? $entity->setPublished() : $entity->setUnpublished();
173       }
174     }
175   }
176
177 }