Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / content_moderation / src / ModerationInformation.php
1 <?php
2
3 namespace Drupal\content_moderation;
4
5 use Drupal\Core\Entity\ContentEntityInterface;
6 use Drupal\Core\Entity\EntityInterface;
7 use Drupal\Core\Entity\EntityPublishedInterface;
8 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
9 use Drupal\Core\Entity\EntityTypeInterface;
10 use Drupal\Core\Entity\EntityTypeManagerInterface;
11 use Drupal\Core\TypedData\TranslatableInterface;
12 use Drupal\Core\StringTranslation\StringTranslationTrait;
13
14 /**
15  * General service for moderation-related questions about Entity API.
16  */
17 class ModerationInformation implements ModerationInformationInterface {
18
19   use StringTranslationTrait;
20
21   /**
22    * The entity type manager.
23    *
24    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
25    */
26   protected $entityTypeManager;
27
28   /**
29    * The bundle information service.
30    *
31    * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
32    */
33   protected $bundleInfo;
34
35   /**
36    * Creates a new ModerationInformation instance.
37    *
38    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
39    *   The entity type manager.
40    * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info
41    *   The bundle information service.
42    */
43   public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_info) {
44     $this->entityTypeManager = $entity_type_manager;
45     $this->bundleInfo = $bundle_info;
46   }
47
48   /**
49    * {@inheritdoc}
50    */
51   public function isModeratedEntity(EntityInterface $entity) {
52     if (!$entity instanceof ContentEntityInterface) {
53       return FALSE;
54     }
55
56     return $this->shouldModerateEntitiesOfBundle($entity->getEntityType(), $entity->bundle());
57   }
58
59   /**
60    * {@inheritdoc}
61    */
62   public function canModerateEntitiesOfEntityType(EntityTypeInterface $entity_type) {
63     return $entity_type->hasHandlerClass('moderation');
64   }
65
66   /**
67    * {@inheritdoc}
68    */
69   public function shouldModerateEntitiesOfBundle(EntityTypeInterface $entity_type, $bundle) {
70     if ($this->canModerateEntitiesOfEntityType($entity_type)) {
71       $bundles = $this->bundleInfo->getBundleInfo($entity_type->id());
72       return isset($bundles[$bundle]['workflow']);
73     }
74     return FALSE;
75   }
76
77   /**
78    * {@inheritdoc}
79    */
80   public function getLatestRevision($entity_type_id, $entity_id) {
81     if ($latest_revision_id = $this->getLatestRevisionId($entity_type_id, $entity_id)) {
82       return $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($latest_revision_id);
83     }
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   public function getLatestRevisionId($entity_type_id, $entity_id) {
90     if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) {
91       $result = $storage->getQuery()
92         ->latestRevision()
93         ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id)
94         // No access check is performed here since this is an API function and
95         // should return the same ID regardless of the current user.
96         ->accessCheck(FALSE)
97         ->execute();
98       if ($result) {
99         return key($result);
100       }
101     }
102   }
103
104   /**
105    * {@inheritdoc}
106    */
107   public function getDefaultRevisionId($entity_type_id, $entity_id) {
108     if ($storage = $this->entityTypeManager->getStorage($entity_type_id)) {
109       $result = $storage->getQuery()
110         ->currentRevision()
111         ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id)
112         // No access check is performed here since this is an API function and
113         // should return the same ID regardless of the current user.
114         ->accessCheck(FALSE)
115         ->execute();
116       if ($result) {
117         return key($result);
118       }
119     }
120   }
121
122   /**
123    * {@inheritdoc}
124    */
125   public function getAffectedRevisionTranslation(ContentEntityInterface $entity) {
126     foreach ($entity->getTranslationLanguages() as $language) {
127       $translation = $entity->getTranslation($language->getId());
128       if (!$translation->isDefaultRevision() && $translation->isRevisionTranslationAffected()) {
129         return $translation;
130       }
131     }
132   }
133
134   /**
135    * {@inheritdoc}
136    */
137   public function isLatestRevision(ContentEntityInterface $entity) {
138     return $entity->getRevisionId() == $this->getLatestRevisionId($entity->getEntityTypeId(), $entity->id());
139   }
140
141   /**
142    * {@inheritdoc}
143    */
144   public function hasPendingRevision(ContentEntityInterface $entity) {
145     $result = FALSE;
146     if ($this->isModeratedEntity($entity)) {
147       /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
148       $storage = $this->entityTypeManager->getStorage($entity->getEntityTypeId());
149       $latest_revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $entity->language()->getId());
150       $default_revision_id = $entity->isDefaultRevision() && !$entity->isNewRevision() && ($revision_id = $entity->getRevisionId()) ?
151         $revision_id : $this->getDefaultRevisionId($entity->getEntityTypeId(), $entity->id());
152       if ($latest_revision_id != $default_revision_id) {
153         /** @var \Drupal\Core\Entity\ContentEntityInterface $latest_revision */
154         $latest_revision = $storage->loadRevision($latest_revision_id);
155         $result = !$latest_revision->wasDefaultRevision();
156       }
157     }
158     return $result;
159   }
160
161   /**
162    * {@inheritdoc}
163    */
164   public function isLiveRevision(ContentEntityInterface $entity) {
165     $workflow = $this->getWorkflowForEntity($entity);
166     return $this->isLatestRevision($entity)
167       && $entity->isDefaultRevision()
168       && $entity->moderation_state->value
169       && $workflow->getTypePlugin()->getState($entity->moderation_state->value)->isPublishedState();
170   }
171
172   /**
173    * {@inheritdoc}
174    */
175   public function isDefaultRevisionPublished(ContentEntityInterface $entity) {
176     $workflow = $this->getWorkflowForEntity($entity);
177     $default_revision = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId())->load($entity->id());
178     // If no default revision could be loaded, the entity has not yet been
179     // saved. In this case the moderation_state of the unsaved entity can be
180     // used, since once saved it will become the default.
181     $default_revision = $default_revision  ?: $entity;
182
183     // Ensure we are checking all translations of the default revision.
184     if ($default_revision instanceof TranslatableInterface && $default_revision->isTranslatable()) {
185       // Loop through each language that has a translation.
186       foreach ($default_revision->getTranslationLanguages() as $language) {
187         // Load the translated revision.
188         $translation = $default_revision->getTranslation($language->getId());
189         // If the moderation state is empty, it was not stored yet so no point
190         // in doing further work.
191         $moderation_state = $translation->moderation_state->value;
192         if (!$moderation_state) {
193           continue;
194         }
195         // Return TRUE if a translation with a published state is found.
196         if ($workflow->getTypePlugin()->getState($moderation_state)->isPublishedState()) {
197           return TRUE;
198         }
199       }
200     }
201
202     return $workflow->getTypePlugin()->getState($default_revision->moderation_state->value)->isPublishedState();
203   }
204
205   /**
206    * {@inheritdoc}
207    */
208   public function getWorkflowForEntity(ContentEntityInterface $entity) {
209     $bundles = $this->bundleInfo->getBundleInfo($entity->getEntityTypeId());
210     if (isset($bundles[$entity->bundle()]['workflow'])) {
211       return $this->entityTypeManager->getStorage('workflow')->load($bundles[$entity->bundle()]['workflow']);
212     };
213     return NULL;
214   }
215
216   /**
217    * {@inheritdoc}
218    */
219   public function getUnsupportedFeatures(EntityTypeInterface $entity_type) {
220     $features = [];
221     // Test if entity is publishable.
222     if (!$entity_type->entityClassImplements(EntityPublishedInterface::class)) {
223       $features['publishing'] = $this->t("@entity_type_plural_label do not support publishing statuses. For example, even after transitioning from a published workflow state to an unpublished workflow state they will still be visible to site visitors.", ['@entity_type_plural_label' => $entity_type->getCollectionLabel()]);
224     }
225     return $features;
226   }
227
228 }