entityTypeManager = $entity_type_manager; $this->moderationInformation = $moderation_information; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('entity_type.manager'), $container->get('content_moderation.moderation_information') ); } /** * {@inheritdoc} */ public function validate($value, Constraint $constraint) { /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $value->getEntity(); // Ignore entities that are not subject to moderation anyway. if (!$this->moderationInformation->isModeratedEntity($entity)) { return; } $workflow = $this->moderationInformation->getWorkflowForEntity($entity); if (!$workflow->getTypePlugin()->hasState($entity->moderation_state->value)) { // If the state we are transitioning to doesn't exist, we can't validate // the transitions for this entity further. $this->context->addViolation($constraint->invalidStateMessage, [ '%state' => $entity->moderation_state->value, '%workflow' => $workflow->label(), ]); return; } // If a new state is being set and there is an existing state, validate // there is a valid transition between them. if (!$entity->isNew() && !$this->isFirstTimeModeration($entity)) { $original_entity = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->loadRevision($entity->getLoadedRevisionId()); if (!$entity->isDefaultTranslation() && $original_entity->hasTranslation($entity->language()->getId())) { $original_entity = $original_entity->getTranslation($entity->language()->getId()); } // If the state of the original entity doesn't exist on the workflow, // we cannot do any further validation of transitions, because none will // be setup for a state that doesn't exist. Instead allow any state to // take its place. if (!$workflow->getTypePlugin()->hasState($original_entity->moderation_state->value)) { return; } $new_state = $workflow->getTypePlugin()->getState($entity->moderation_state->value); $original_state = $workflow->getTypePlugin()->getState($original_entity->moderation_state->value); if (!$original_state->canTransitionTo($new_state->id())) { $this->context->addViolation($constraint->message, [ '%from' => $original_state->label(), '%to' => $new_state->label() ]); } } } /** * Determines if this entity is being moderated for the first time. * * If the previous version of the entity has no moderation state, we assume * that means it predates the presence of moderation states. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity being moderated. * * @return bool * TRUE if this is the entity's first time being moderated, FALSE otherwise. */ protected function isFirstTimeModeration(EntityInterface $entity) { $original_entity = $this->moderationInformation->getLatestRevision($entity->getEntityTypeId(), $entity->id()); if ($original_entity) { $original_id = $original_entity->moderation_state; } return !($entity->moderation_state && $original_entity && $original_id); } }