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;
class TransitionManager {
use StringTranslationTrait;
protected $moderationInformation;
protected $currentUser;
protected $entityTypeManager;
protected $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 function getStates(ContentEntityInterface $entity) {
$states = [];
$workflow = $this->moderationInformation
->getWorkflowForEntity($entity);
foreach ($workflow
->getTypePlugin()
->getTransitions() as $transition) {
$base_permission = $workflow
->id() . ' transition ' . $transition
->id();
if ($this->currentUser
->hasPermission("schedule {$base_permission}") || $this->currentUser
->hasPermission("use {$base_permission}")) {
$to_state = $transition
->to();
$states[$to_state
->id()] = $to_state
->label();
}
}
return $states;
}
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;
$format_options = [
'timezone' => drupal_get_user_timezone(),
];
foreach ($data as $transition) {
if (empty($transition['when'])) {
$form_state
->setError($element, t('Scheduled transitions must have a date and time.'));
return;
}
$date_time = new DrupalDateTime($transition['when'], 'UTC');
if ($date_time
->hasErrors()) {
$variables = [
'%when' => $transition['when'],
];
$form_state
->setError($element, t('"%when" is not a valid date and time.', $variables));
return;
}
if ($minimum_date instanceof DrupalDateTime && $date_time
->getTimestamp() < $minimum_date
->getTimestamp()) {
$variables = [
'@date' => $minimum_date
->format('F j, Y', $format_options),
'@time' => $minimum_date
->format('g:i A', $format_options),
];
$form_state
->setError($element, t('You cannot schedule a transition to take place before @time on @date.', $variables));
return;
}
$minimum_date = $date_time;
}
}
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();
}
}
protected 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));
}
}
}