View source
<?php
namespace Drupal\scheduled_publish\Service;
use DateTime;
use DateTimeZone;
use Drupal\Component\Datetime\Time;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\content_moderation\ModerationInformationInterface;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfo;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\scheduled_publish\Plugin\Field\FieldType\ScheduledPublish;
class ScheduledPublishCron {
public static $supportedTypes = [
'node',
'media',
];
private $entityBundleInfoService;
private $entityFieldManager;
private $entityTypeManager;
private $dateTime;
protected $moderationInfo;
protected $logger;
public function __construct(EntityTypeBundleInfoInterface $entityBundleInfo, EntityFieldManagerInterface $entityFieldManager, EntityTypeManagerInterface $entityTypeManager, TimeInterface $dateTime, ModerationInformationInterface $moderation_info, LoggerChannelFactoryInterface $logger) {
$this->entityBundleInfoService = $entityBundleInfo;
$this->entityFieldManager = $entityFieldManager;
$this->entityTypeManager = $entityTypeManager;
$this->dateTime = $dateTime;
$this->moderationInfo = $moderation_info;
$this->logger = $logger;
}
public function doUpdate() : void {
foreach (self::$supportedTypes as $supportedType) {
$this
->doUpdateFor($supportedType);
}
}
private function doUpdateFor($entityType) {
$bundles = $this->entityBundleInfoService
->getBundleInfo($entityType);
foreach ($bundles as $bundleName => $value) {
$scheduledFields = $this
->getScheduledFields($entityType, $bundleName);
if (\count($scheduledFields) > 0) {
foreach ($scheduledFields as $scheduledField) {
$query = $this->entityTypeManager
->getStorage($entityType)
->getQuery('AND');
$query
->condition($entityType === 'media' ? 'bundle' : 'type', $bundleName);
$query
->condition($scheduledField, NULL, 'IS NOT NULL');
$query
->accessCheck(FALSE);
$query
->latestRevision();
$entities = $query
->execute();
foreach ($entities as $entityRevision => $entityId) {
$entity = $this->entityTypeManager
->getStorage($entityType)
->loadRevision($entityRevision);
$this
->updateEntityField($entity, $scheduledField);
}
}
}
}
}
private function getScheduledFields(string $entityTypeName, string $bundleName) : array {
$scheduledFields = [];
$fields = $this->entityFieldManager
->getFieldDefinitions($entityTypeName, $bundleName);
foreach ($fields as $fieldName => $field) {
if (strpos($fieldName, 'field_') !== FALSE) {
if ($field
->getType() === 'scheduled_publish') {
$scheduledFields[] = $fieldName;
}
}
}
return $scheduledFields;
}
private function updateEntityField(ContentEntityBase $entity, string $scheduledField) : void {
$scheduledEntity = $entity
->get($scheduledField);
$scheduledValue = $scheduledEntity
->getValue();
if (empty($scheduledValue)) {
return;
}
foreach ($scheduledValue as $key => $value) {
if ($this
->getTimestampFromIso8601($value['value']) <= $this->dateTime
->getCurrentTime()) {
unset($scheduledValue[$key]);
$this
->updateEntity($entity, $value['moderation_state'], $scheduledField, $scheduledValue);
}
}
}
private function getTimestampFromIso8601(string $dateIso8601) : int {
$datetime = new DateTime($dateIso8601, new DateTimeZone(ScheduledPublish::STORAGE_TIMEZONE));
$datetime
->setTimezone(new \DateTimeZone(date_default_timezone_get()));
return $datetime
->getTimestamp();
}
private function updateEntity(ContentEntityBase $entity, string $moderationState, string $scheduledPublishField, $scheduledValue) : void {
$entity
->set($scheduledPublishField, $scheduledValue);
if ($this
->isValidStateChange($entity, $moderationState)) {
$currentModerationState = $entity
->get('moderation_state')
->getValue()[0]['value'];
$entity
->set('moderation_state', $moderationState);
}
$entity
->save();
if (isset($currentModerationState)) {
$entity_info = $entity
->label() . ' (' . $entity
->id() . ')';
$this->logger
->get('scheduled_publish')
->info('The moderation state of @entity was changed from @orig_status to @current_status', [
'@entity' => $entity_info,
'@orig_status' => $currentModerationState,
'@current_status' => $moderationState,
]);
}
}
protected function isValidStateChange(ContentEntityBase $entity, string $moderationState) : bool {
$workflow = $this->moderationInfo
->getWorkflowForEntity($entity);
$current_state = $entity->moderation_state->value ? $workflow
->getTypePlugin()
->getState($entity->moderation_state->value) : $workflow
->getTypePlugin()
->getInitialState($entity);
$transitions = $current_state
->getTransitions();
foreach ($transitions as $key => $value) {
if ($value
->to()
->id() === $moderationState) {
return TRUE;
}
}
return FALSE;
}
}