View source
<?php
namespace Drupal\lightning_scheduler;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
use Drupal\lightning_core\Element;
final class Migrator {
use StringTranslationTrait;
protected $entityTypeManager;
protected $database;
protected $state;
protected $messenger;
public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, StateInterface $state, MessengerInterface $messenger, TranslationInterface $translation = NULL) {
$this->entityTypeManager = $entity_type_manager;
$this->database = $database;
$this->state = $state;
$this->messenger = $messenger;
if ($translation) {
$this
->setStringTranslation($translation);
}
}
public function getMigrations() {
return $this->state
->get('lightning_scheduler.migrations', []);
}
public function setMigrations(array $migrations) {
return $this->state
->set('lightning_scheduler.migrations', $migrations);
}
public function getEntityTypesToMigrate(array $limit = []) {
$filter = function (EntityTypeInterface $entity_type) {
return $entity_type
->entityClassImplements(ContentEntityInterface::class);
};
$entity_types = array_filter($this->entityTypeManager
->getDefinitions(), $filter);
$migrations = $limit ?: $this
->getMigrations();
$migrations = array_flip($migrations);
return array_intersect_key($entity_types, $migrations);
}
public function query($entity_type_id) {
$entity_type = $this->entityTypeManager
->getDefinition($entity_type_id);
$fields = [
$entity_type
->getKey('id'),
'scheduled_publication',
'scheduled_moderation_state',
];
if ($entity_type
->isRevisionable()) {
array_push($fields, $entity_type
->getKey('revision'));
}
if ($entity_type
->isTranslatable()) {
array_push($fields, $entity_type
->getKey('langcode'));
}
$table = $entity_type
->getRevisionDataTable() ?: $entity_type
->getDataTable();
return $this->database
->select($table)
->fields($table, $fields)
->isNotNull('scheduled_publication')
->isNotNull('scheduled_moderation_state');
}
public function migrateAll($entity_type_id, callable $callback = NULL) {
$items = $this
->query($entity_type_id)
->execute();
$count = 0;
foreach ($items as $item) {
$this
->migrate($entity_type_id, $item);
if ($callback) {
$callback($entity_type_id, ++$count, $item, $this);
}
}
$this
->completeMigration($entity_type_id);
return $count;
}
public function migrate($entity_type_id, $item) {
$storage = $this->entityTypeManager
->getStorage($entity_type_id);
$entity = $this
->load($storage, $item);
$entity->existingRevisionId = $entity
->getRevisionId();
$entity
->set('scheduled_transition_date', $item->scheduled_publication)
->set('scheduled_transition_state', $item->scheduled_moderation_state)->original
->set('scheduled_transition_date', NULL)
->set('scheduled_transition_state', NULL);
$storage
->save($entity);
}
public function purge($entity_type_id, $field_name) {
$storage = $this->entityTypeManager
->getStorage($entity_type_id);
if ($storage instanceof SqlEntityStorageInterface) {
$table_mapping = $storage
->getTableMapping();
$values = [];
foreach ($table_mapping
->getColumnNames($field_name) as $column) {
$values[$column] = NULL;
}
$this->database
->update($table_mapping
->getFieldTableName($field_name))
->fields($values)
->execute();
}
}
protected function load(EntityStorageInterface $storage, $item) {
$entity_type = $storage
->getEntityType();
$id_key = $entity_type
->getKey('id');
if ($entity_type
->isRevisionable()) {
$vid_key = $entity_type
->getKey('revision');
}
if ($entity_type
->isTranslatable()) {
$language_key = $entity_type
->getKey('langcode');
}
$entity = isset($vid_key) ? $storage
->loadRevision($item->{$vid_key}) : $storage
->load($item->{$id_key});
if (isset($language_key)) {
$entity = $entity
->getTranslation($item->{$language_key});
}
$entity->original = $storage
->loadUnchanged($item->{$id_key});
return $entity;
}
public function completeMigration($entity_type_id) {
$storage = $this->entityTypeManager
->getStorage('base_field_override');
$overridden_fields = $storage
->getQuery()
->condition('entity_type', $entity_type_id)
->condition('field_name', [
'scheduled_publication',
'scheduled_moderation_state',
])
->execute();
if ($overridden_fields) {
$overridden_fields = $storage
->loadMultiple($overridden_fields);
$storage
->delete($overridden_fields);
$message = $this
->t('Overridden scheduled_publication and scheduled_moderation_state fields were detected. They have been reverted, but you must remember to remove them from your exported config.');
$this->messenger
->addWarning($message);
}
$migrations = array_diff($this
->getMigrations(), [
$entity_type_id,
]);
$this
->setMigrations($migrations);
}
public function generatePreMigrationMessage(array $entity_types, $html = TRUE) {
$entity_types = $this
->entityTypeOptions($entity_types);
$variables = [
'@entity_types' => Element::oxford($entity_types),
':maintenance_mode' => Url::fromRoute('system.site_maintenance_mode')
->toString(),
];
return $html ? $this
->t('You are about to migrate scheduled transitions for all @entity_types. This will modify your existing content and may take a long time if you have a huge site with tens of thousands of pieces of content. <strong>You cannot undo this</strong>, so you may want to <strong>back up your database</strong> and <a href=":maintenance_mode">switch to maintenance mode</a> before continuing.', $variables) : $this
->t('You are about to migrate scheduled transitions for all @entity_types. This will modify your existing content and may take a long time if you have a huge site with tens of thousands of pieces of content. You cannot undo this, so you may want to back up your database and switch to maintenance mode before continuing.', $variables);
}
public function entityTypeOptions(array $entity_types) {
$to_option = function (EntityTypeInterface $entity_type) {
return $entity_type
->getPluralLabel();
};
return array_map($to_option, $entity_types);
}
}