View source
<?php
declare (strict_types=1);
namespace Drupal\scheduled_transitions;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\RevisionLogInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Utility\Token;
use Drupal\scheduled_transitions\Entity\ScheduledTransition;
use Drupal\scheduled_transitions\Entity\ScheduledTransitionInterface;
use Drupal\scheduled_transitions\Event\ScheduledTransitionsEvents;
use Drupal\scheduled_transitions\Event\ScheduledTransitionsNewRevisionEvent;
use Drupal\scheduled_transitions\Exception\ScheduledTransitionMissingEntity;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ScheduledTransitionsRunner implements ScheduledTransitionsRunnerInterface {
use StringTranslationTrait;
protected const LOCK_DURATION = 1800;
protected $entityTypeManager;
protected $time;
protected $logger;
protected $moderationInformation;
protected $token;
protected $configFactory;
protected $eventDispatcher;
public function __construct(EntityTypeManagerInterface $entityTypeManager, ConfigFactoryInterface $configFactory, TimeInterface $time, LoggerInterface $logger, ModerationInformationInterface $moderationInformation, Token $token, EventDispatcherInterface $eventDispatcher) {
$this->entityTypeManager = $entityTypeManager;
$this->configFactory = $configFactory;
$this->time = $time;
$this->logger = $logger;
$this->moderationInformation = $moderationInformation;
$this->token = $token;
$this->eventDispatcher = $eventDispatcher;
}
public function runTransition(ScheduledTransitionInterface $scheduledTransition) : void {
$scheduledTransitionId = $scheduledTransition
->id();
$targs = [
'@id' => $scheduledTransitionId,
];
$entity = $scheduledTransition
->getEntity();
if (!$entity) {
$this->logger
->info('Entity does not exist for scheduled transition #@id', $targs);
throw new ScheduledTransitionMissingEntity(sprintf('Entity does not exist for scheduled transition #%s', $scheduledTransitionId));
}
$event = new ScheduledTransitionsNewRevisionEvent($scheduledTransition);
$this->eventDispatcher
->dispatch(ScheduledTransitionsEvents::NEW_REVISION, $event);
$newRevision = $event
->getNewRevision();
if (!$newRevision) {
throw new ScheduledTransitionMissingEntity(sprintf('No revision could be determined to transition to for scheduled transition #%s', $scheduledTransitionId));
}
$entityStorage = $this->entityTypeManager
->getStorage($entity
->getEntityTypeId());
$latestRevisionId = $entityStorage
->getLatestRevisionId($entity
->id());
if ($latestRevisionId) {
$latest = $entityStorage
->loadRevision($latestRevisionId);
}
if (!isset($latest)) {
$this->logger
->info('Latest revision does not exist for scheduled transition #@id', $targs);
throw new ScheduledTransitionMissingEntity(sprintf('Latest revision does not exist for scheduled transition #%s', $scheduledTransitionId));
}
$this
->transitionEntity($scheduledTransition, $newRevision, $latest);
$this->logger
->info('Deleted scheduled transition #@id', $targs);
$scheduledTransition
->delete();
}
protected function transitionEntity(ScheduledTransitionInterface $scheduledTransition, EntityInterface $newRevision, EntityInterface $latest) : void {
$entityStorage = $this->entityTypeManager
->getStorage($newRevision
->getEntityTypeId());
$settings = $this->configFactory
->get('scheduled_transitions.settings');
$isLatestRevisionPublished = $this->moderationInformation
->isLiveRevision($latest);
$entityRevisionId = $newRevision
->getRevisionId();
$workflow = $this->moderationInformation
->getWorkflowForEntity($latest);
$workflowPlugin = $workflow
->getTypePlugin();
$states = $workflowPlugin
->getStates();
$originalNewRevisionState = $states[$newRevision->moderation_state->value ?? ''] ?? NULL;
$originalLatestState = $states[$latest->moderation_state->value ?? ''] ?? NULL;
$newState = $states[$scheduledTransition
->getState()] ?? NULL;
$targs = [
'@revision_id' => $entityRevisionId,
'@original_state' => $originalNewRevisionState ? $originalNewRevisionState
->label() : $this
->t('- Unknown state -'),
'@new_state' => $newState
->label(),
'@original_revision_id' => $latest
->getRevisionId(),
'@original_latest_state' => $originalLatestState ? $originalLatestState
->label() : $this
->t('- Unknown state -'),
];
$tokenData = [
'scheduled-transitions' => [
'to-state' => $targs['@new_state'],
'from-state' => $targs['@original_state'],
'from-revision-id' => $targs['@revision_id'],
'latest-state' => $targs['@original_latest_state'],
'latest-revision-id' => $targs['@original_revision_id'],
],
];
$newIsLatest = $newRevision
->getRevisionId() === $latest
->getRevisionId();
$newRevision = $entityStorage
->createRevision($newRevision, FALSE);
$newRevision->moderation_state = $newState
->id();
if ($newRevision instanceof EntityChangedInterface) {
$newRevision
->setChangedTime($this->time
->getRequestTime());
}
if ($newIsLatest) {
$this->logger
->info('Transitioning latest revision from @original_state to @new_state', $targs);
if ($newRevision instanceof RevisionLogInterface) {
$template = $settings
->get('message_transition_latest');
$log = $this->token
->replace($template, $tokenData);
$newRevision
->setRevisionLogMessage($log);
$newRevision
->setRevisionCreationTime($this->time
->getRequestTime());
}
$newRevision
->save();
}
else {
$this->logger
->info('Copied revision #@revision_id and changed from @original_state to @new_state', $targs);
if ($newRevision instanceof RevisionLogInterface) {
$template = $settings
->get('message_transition_historical');
$log = $this->token
->replace($template, $tokenData);
$newRevision
->setRevisionLogMessage($log);
$newRevision
->setRevisionCreationTime($this->time
->getRequestTime());
}
$newRevision
->save();
$options = $scheduledTransition
->getOptions();
if (!empty($options[ScheduledTransition::OPTION_RECREATE_NON_DEFAULT_HEAD])) {
if (!$isLatestRevisionPublished && $originalLatestState) {
$latest = $entityStorage
->createRevision($latest, FALSE);
$this->logger
->info('Reverted @original_latest_state revision #@original_revision_id back to top', $targs);
if ($latest instanceof RevisionLogInterface) {
$template = $settings
->get('message_transition_copy_latest_draft');
$log = $this->token
->replace($template, $tokenData);
$latest
->setRevisionLogMessage($log);
$latest
->setRevisionCreationTime($this->time
->getRequestTime());
}
$latest
->save();
}
}
}
}
}