View source
<?php
namespace Drupal\entity_update;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityTypeInterface;
class EntityUpdate {
public static function basicUpdate($force = FALSE) {
$flgOK = TRUE;
try {
$list = self::getEntityTypesToUpdate();
foreach ($list as $item => $entity_type_changes) {
if (!empty(\Drupal::entityQuery($item)
->execute())) {
$flgOK = FALSE;
EntityUpdatePrint::drushLog("The entity '{$item}' is not empty", 'warning');
}
}
} catch (\Exception $e) {
EntityUpdatePrint::drushLog($e
->getMessage(), 'error', NULL, TRUE);
$flgOK = FALSE;
}
if (!$flgOK && !$force) {
EntityUpdatePrint::drushLog("Cant update as basic, use --all or --force option", 'cancel', NULL, TRUE);
EntityUpdatePrint::drushPrint("Example : drush upe --basic --force --nobackup");
return FALSE;
}
try {
\Drupal::classResolver()
->getInstanceFromDefinition(CustomEntityDefinitionUpdateManager::class)
->applyUpdates();
return !\Drupal::entityDefinitionUpdateManager()
->needsUpdates();
} catch (\Exception $e) {
EntityUpdatePrint::drushLog($e
->getMessage(), 'warning', NULL, TRUE);
}
return FALSE;
}
public static function safeUpdateMain(EntityTypeInterface $entity_type = NULL) {
$entity_change_summerys = self::getEntityTypesToUpdate();
if (empty($entity_change_summerys)) {
EntityUpdatePrint::drushLog('No entities to update.', 'cancel');
return TRUE;
}
if ($entity_type) {
$entity_type_id = $entity_type
->id();
foreach ($entity_change_summerys as $type_id => $entity_type_changes) {
if ($type_id !== $entity_type_id) {
unset($entity_change_summerys[$type_id]);
}
}
if (empty($entity_change_summerys)) {
EntityUpdatePrint::drushLog("No updates for {$entity_type_id}", 'cancel');
return TRUE;
}
else {
return self::safeUpdateEntityType($entity_type);
}
return FALSE;
}
$flg_has_updated = FALSE;
$flg_has_install = FALSE;
foreach ($entity_change_summerys as $entity_type_changes) {
foreach ($entity_type_changes as $entity_change_summ) {
if (strstr($entity_change_summ, "updated")) {
$flg_has_updated = TRUE;
}
elseif (strstr($entity_change_summ, "uninstalled")) {
$flg_has_updated = TRUE;
}
else {
$flg_has_install = TRUE;
}
}
}
if (!$flg_has_install && !$flg_has_updated) {
EntityUpdatePrint::drushLog('Entity Install / Uninstall / Update not found.', 'cancel');
return FALSE;
}
elseif ($flg_has_install && $flg_has_updated) {
EntityUpdatePrint::drushLog('Has fields to install and to uninstall. Do one action at a time.', 'cancel');
return FALSE;
}
elseif ($flg_has_updated) {
return self::safeUpdateFields($entity_change_summerys);
}
elseif ($flg_has_install) {
return self::safeUpdateInstallFields();
}
EntityUpdatePrint::drushLog('UNKNOWN ERROR.', 'error');
return FALSE;
}
private static function safeUpdateFields($entity_change_summerys) {
EntityUpdatePrint::drushPrint("Read and backup data");
$flg_has_data = self::entityUpdateDataBackupDel($entity_change_summerys);
EntityUpdatePrint::drushPrint("Update entity Schema");
try {
\Drupal::classResolver()
->getInstanceFromDefinition(CustomEntityDefinitionUpdateManager::class)
->applyUpdates();
EntityUpdatePrint::drushLog('Entities update success', 'ok');
} catch (Exception $ex) {
EntityUpdatePrint::drushLog($ex
->getMessage(), 'warning');
}
if ($flg_has_data) {
EntityUpdatePrint::drushPrint("Re creating entities.");
$result = self::entityUpdateDataRestore();
EntityUpdatePrint::drushLog("Entiti recreate Success / End", $result ? 'ok' : 'warning');
EntityUpdatePrint::drushLog("CAUTION : Before next operation, Flush 'Entity Data' using : drush upe --clean", 'warning');
}
return !\Drupal::entityDefinitionUpdateManager()
->needsUpdates();
}
public static function entityUpdateDataBackupDel($entity_change_summerys, $force_type = NULL) {
if (empty($entity_change_summerys) && $force_type) {
$entity_change_summerys[$force_type] = 1;
}
$con = Database::getConnection();
$excludes = EntityUpdateHelper::getConfig()
->get('excludes');
$flg_has_data = FALSE;
EntityUpdatePrint::drushPrint("Read and backup data");
foreach ($entity_change_summerys as $entity_type_id => $entity_type_changes) {
if (empty($excludes[$entity_type_id])) {
EntityUpdatePrint::drushPrint(" - Reading : {$entity_type_id}");
$entities = \Drupal::entityTypeManager()
->getStorage($entity_type_id)
->loadMultiple();
foreach ($entities as $entity_id => $entity) {
$entity_type = $entity
->getEntityType();
$con
->insert('entity_update')
->fields([
'entity_type' => $entity_type_id,
'entity_id' => $entity_id,
'entity_class' => $entity_type
->getClass(),
'status' => 0,
'data' => Json::encode($entity
->toArray()),
])
->execute();
$entity
->delete();
$flg_has_data = TRUE;
}
EntityUpdatePrint::drushLog("Backup ok", 'ok');
}
else {
EntityUpdatePrint::drushLog("Deletation of {$entity_type_id} is excluded by config.", 'cancel');
}
}
return $flg_has_data;
}
public static function entityUpdateDataRestore() {
$con = Database::getConnection();
$db_data = $con
->select('entity_update', 't')
->fields('t')
->execute()
->fetchAll(\PDO::FETCH_ASSOC);
if (!$db_data) {
EntityUpdatePrint::drushLog("ERROR, Data read error", 'error');
return FALSE;
}
foreach ($db_data as $row) {
$entity_class = $row['entity_class'];
$entity_data = Json::decode($row['data']);
$entity = $entity_class::create($entity_data);
$entity
->save();
}
return TRUE;
}
private static function safeUpdateInstallFields() {
try {
\Drupal::classResolver()
->getInstanceFromDefinition(CustomEntityDefinitionUpdateManager::class)
->applyUpdates();
EntityUpdatePrint::drushLog('Entities update success', 'ok');
return !\Drupal::entityDefinitionUpdateManager()
->needsUpdates();
} catch (\Exception $e) {
EntityUpdatePrint::drushLog($e
->getMessage(), 'warning');
}
return FALSE;
}
private static function safeUpdateEntityType(EntityTypeInterface $entity_type) {
$entity_change_summerys = self::getEntityTypesToUpdate($entity_type
->id());
$flg_done = FALSE;
try {
$update_manager = entity_update_get_entity_definition_update_manager();
$complete_change_list = $update_manager
->getChangeList();
if ($complete_change_list) {
$update_manager->entityTypeManager
->clearCachedDefinitions();
}
foreach ($complete_change_list as $entity_type_id => $change_list) {
if ($entity_type_id === $entity_type
->id()) {
$flg_has_install = FALSE;
foreach ($entity_change_summerys[$entity_type_id] as $entity_change_summ) {
if (strstr($entity_change_summ, "uninstalled")) {
}
else {
$flg_has_install = TRUE;
}
}
if (!$flg_has_install) {
$entity_change_summerys = [
$entity_type_id => 1,
];
$flg_has_data = self::entityUpdateDataBackupDel($entity_change_summerys);
}
else {
$flg_has_data = FALSE;
}
if (!empty($change_list['entity_type'])) {
$update_manager
->doEntityUpdate($change_list['entity_type'], $entity_type_id);
}
if (!empty($change_list['field_storage_definitions'])) {
$storage_definitions = $update_manager->entityFieldManager
->getFieldStorageDefinitions($entity_type_id);
$original_storage_definitions = $update_manager->entityLastInstalledSchemaRepository
->getLastInstalledFieldStorageDefinitions($entity_type_id);
foreach ($change_list['field_storage_definitions'] as $field_name => $change) {
$storage_definition = isset($storage_definitions[$field_name]) ? $storage_definitions[$field_name] : NULL;
$original_storage_definition = isset($original_storage_definitions[$field_name]) ? $original_storage_definitions[$field_name] : NULL;
$update_manager
->doFieldUpdate($change, $storage_definition, $original_storage_definition);
}
}
if ($flg_has_data) {
$result = self::entityUpdateDataRestore();
if ($result) {
self::cleanupEntityBackup();
}
}
$flg_done = TRUE;
}
}
} catch (Exception $e) {
EntityUpdatePrint::drushLog($e
->getMessage(), 'error');
return FALSE;
}
return $flg_done;
}
public static function cleanupEntityBackup() {
$con = Database::getConnection();
$con
->truncate('entity_update')
->execute();
return TRUE;
}
public static function getEntityTypesToUpdate($type_id = NULL) {
$list = entity_update_get_entity_changes();
foreach ($list as $entity_type_id => $entity_change_summery) {
if (!$type_id || $type_id == $entity_type_id) {
$list[$entity_type_id] = $entity_change_summery;
}
}
return $list;
}
}