4b879737dae519ed5fb2bb89cea0da772d2824bf
[yaffs-website] / web / core / modules / content_moderation / src / Plugin / Validation / Constraint / ModerationStateConstraintValidator.php
1 <?php
2
3 namespace Drupal\content_moderation\Plugin\Validation\Constraint;
4
5 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
6 use Drupal\Core\Entity\EntityInterface;
7 use Drupal\Core\Entity\EntityTypeManagerInterface;
8 use Drupal\content_moderation\ModerationInformationInterface;
9 use Symfony\Component\DependencyInjection\ContainerInterface;
10 use Symfony\Component\Validator\Constraint;
11 use Symfony\Component\Validator\ConstraintValidator;
12
13 /**
14  * Checks if a moderation state transition is valid.
15  */
16 class ModerationStateConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
17
18   /**
19    * The entity type manager.
20    *
21    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
22    */
23   private $entityTypeManager;
24
25   /**
26    * The moderation info.
27    *
28    * @var \Drupal\content_moderation\ModerationInformationInterface
29    */
30   protected $moderationInformation;
31
32   /**
33    * Creates a new ModerationStateConstraintValidator instance.
34    *
35    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
36    *   The entity type manager.
37    * @param \Drupal\content_moderation\ModerationInformationInterface $moderation_information
38    *   The moderation information.
39    */
40   public function __construct(EntityTypeManagerInterface $entity_type_manager, ModerationInformationInterface $moderation_information) {
41     $this->entityTypeManager = $entity_type_manager;
42     $this->moderationInformation = $moderation_information;
43   }
44
45   /**
46    * {@inheritdoc}
47    */
48   public static function create(ContainerInterface $container) {
49     return new static(
50       $container->get('entity_type.manager'),
51       $container->get('content_moderation.moderation_information')
52     );
53   }
54
55   /**
56    * {@inheritdoc}
57    */
58   public function validate($value, Constraint $constraint) {
59     /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
60     $entity = $value->getEntity();
61
62     // Ignore entities that are not subject to moderation anyway.
63     if (!$this->moderationInformation->isModeratedEntity($entity)) {
64       return;
65     }
66
67     $workflow = $this->moderationInformation->getWorkflowForEntity($entity);
68
69     if (!$workflow->getTypePlugin()->hasState($entity->moderation_state->value)) {
70       // If the state we are transitioning to doesn't exist, we can't validate
71       // the transitions for this entity further.
72       $this->context->addViolation($constraint->invalidStateMessage, [
73         '%state' => $entity->moderation_state->value,
74         '%workflow' => $workflow->label(),
75       ]);
76       return;
77     }
78
79     // If a new state is being set and there is an existing state, validate
80     // there is a valid transition between them.
81     if (!$entity->isNew() && !$this->isFirstTimeModeration($entity)) {
82       $original_entity = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->loadRevision($entity->getLoadedRevisionId());
83       if (!$entity->isDefaultTranslation() && $original_entity->hasTranslation($entity->language()->getId())) {
84         $original_entity = $original_entity->getTranslation($entity->language()->getId());
85       }
86
87       // If the state of the original entity doesn't exist on the workflow,
88       // we cannot do any further validation of transitions, because none will
89       // be setup for a state that doesn't exist. Instead allow any state to
90       // take its place.
91       if (!$workflow->getTypePlugin()->hasState($original_entity->moderation_state->value)) {
92         return;
93       }
94
95       $new_state = $workflow->getTypePlugin()->getState($entity->moderation_state->value);
96       $original_state = $workflow->getTypePlugin()->getState($original_entity->moderation_state->value);
97
98       if (!$original_state->canTransitionTo($new_state->id())) {
99         $this->context->addViolation($constraint->message, [
100           '%from' => $original_state->label(),
101           '%to' => $new_state->label()
102         ]);
103       }
104     }
105   }
106
107   /**
108    * Determines if this entity is being moderated for the first time.
109    *
110    * If the previous version of the entity has no moderation state, we assume
111    * that means it predates the presence of moderation states.
112    *
113    * @param \Drupal\Core\Entity\EntityInterface $entity
114    *   The entity being moderated.
115    *
116    * @return bool
117    *   TRUE if this is the entity's first time being moderated, FALSE otherwise.
118    */
119   protected function isFirstTimeModeration(EntityInterface $entity) {
120     $original_entity = $this->moderationInformation->getLatestRevision($entity->getEntityTypeId(), $entity->id());
121
122     if ($original_entity) {
123       $original_id = $original_entity->moderation_state;
124     }
125
126     return !($entity->moderation_state && $original_entity && $original_id);
127   }
128
129 }