View source
<?php
namespace Drupal\lightning_scheduler;
use Drupal\Component\Serialization\Json;
use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
final class TransitionManager {
use StringTranslationTrait;
private $moderationInformation;
private $currentUser;
private $entityTypeManager;
private $logger;
public function __construct(ModerationInformationInterface $moderation_information, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, LoggerChannelInterface $logger, TranslationInterface $translation = NULL) {
$this->moderationInformation = $moderation_information;
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
$this->logger = $logger;
if ($translation) {
$this
->setStringTranslation($translation);
}
}
public static function validate(array $element, FormStateInterface $form_state) {
$data = Json::decode($element['#value']);
if (json_last_error() !== JSON_ERROR_NONE) {
$variables = [
'%error' => json_last_error_msg(),
];
$form_state
->setError($element, t('Invalid transition data: %error', $variables));
return;
}
if (!is_array($data)) {
$form_state
->setError($element, t('Expected scheduled transitions to be an array.'));
return;
}
$minimum_date = NULL;
foreach ($data as $transition) {
if (empty($transition['when'])) {
$form_state
->setError($element, t('Scheduled transitions must have a date and time.'));
return;
}
if (!preg_match('/^[0-9]+$/', $transition['when'])) {
$variables = [
'%when' => $transition['when'],
];
$form_state
->setError($element, t('"%when" is not a valid date and time.', $variables));
return;
}
if (isset($minimum_date) && $transition['when'] < $minimum_date) {
$variables = [
'@date' => date('F j, Y', $minimum_date),
'@time' => date('g:i A', $minimum_date),
];
$form_state
->setError($element, t('You cannot schedule a transition to take place before @time on @date.', $variables));
return;
}
$minimum_date = $transition['when'];
}
}
public function process($entity_type_id, DrupalDateTime $now) {
foreach ($this
->getTransitionable($entity_type_id, $now) as $entity) {
$error_context = [
'entity_type' => (string) $entity
->getEntityType()
->getSingularLabel(),
'entity' => $entity
->label(),
];
$workflow = $this->moderationInformation
->getWorkflowForEntity($entity);
if (empty($workflow)) {
$message = $this
->t('Could not execute scheduled transition(s) for {entity_type} "{entity}" because no workflow is assigned to it.');
$this->logger
->error($message, $error_context);
continue;
}
$transition_set = new TransitionSet($entity
->get('scheduled_transition_date'), $entity
->get('scheduled_transition_state'));
$to_state = $transition_set
->getExpectedState($now);
if (empty($to_state)) {
continue;
}
$from_state = $entity->moderation_state->value;
$plugin = $workflow
->getTypePlugin();
if ($plugin
->hasTransitionFromStateToState($from_state, $to_state)) {
$entity
->set('moderation_state', $to_state);
}
else {
$error_context += [
'from_state' => $plugin
->getState($from_state)
->label(),
'to_state' => $plugin
->getState($to_state)
->label(),
'workflow' => $workflow
->label(),
];
$message = $this
->t('Could not transition {entity_type} "{entity}" from {from_state} to {to_state} because no such transition exists in the "{workflow}" workflow.');
$this->logger
->warning($message, $error_context);
}
$transition_set
->trim($now);
$entity
->save();
}
}
private function getTransitionable($entity_type_id, DrupalDateTime $now) {
$storage = $this->entityTypeManager
->getStorage($entity_type_id);
$now = $now
->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
$IDs = $storage
->getQuery()
->latestRevision()
->accessCheck(FALSE)
->condition('scheduled_transition_date.value', $now, '<=')
->execute();
foreach (array_keys($IDs) as $revision_id) {
(yield $storage
->loadRevision($revision_id));
}
}
}