entity_legal-4.0.x-dev/entity_legal.install
entity_legal.install
<?php
/**
* @file
* Install, update and uninstall functions for the entity_legal module.
*/
declare(strict_types=1);
use Drupal\Core\Database\Database;
use Drupal\Core\Field\BaseFieldDefinition;
/**
* Implements hook_update_last_removed().
*/
function entity_legal_update_last_removed(): int {
/** @var \Drupal\Core\Update\UpdateHookRegistry $updateHookRegistry */
$updateHookRegistry = \Drupal::service('update.update_hook_registry');
$state = \Drupal::state();
// When running updates, the theme registry is also rebuilt (why?). This
// triggers the 'theme' hooks, including `views_theme()`, which builds the
// Views data. Subsequently, `EntityViewsData::getViewsData()` is called which
// uses the INSTALLED entity type definition, thus the old entity keys, and
// crashes because the current field storage definitions doesn't contain
// anymore the old ID key (name), but the new one (vid). That's why we need to
// install the new definition of 'entity_legal_document_version' very early.
// Unfortunately, the described scenario happens before `hook_update_N()` are
// running. As a workaround, we update the entity type definition here to
// prevent the crash. Only run this once for `entity_legal_update_9002()`.
// @see \views_theme()
// @see \Drupal\views\EntityViewsData::getViewsData()
// @see \entity_legal_update_9002()
if ($updateHookRegistry->getInstalledVersion('entity_legal') === 9001 && !$state->get('entity_legal.update_9002')) {
$updateManager = \Drupal::entityDefinitionUpdateManager();
$entityTypeManager = \Drupal::entityTypeManager();
// Update the 'entity_legal_document_version' entity type definition.
$fieldStorageDefinition = BaseFieldDefinition::create('integer')
->setLabel(t('ID'))
->setReadOnly(TRUE)
->setSetting('unsigned', TRUE);
$updateManager->installFieldStorageDefinition('vid', 'entity_legal_document_version', 'entity_legal', $fieldStorageDefinition);
$entityType = $entityTypeManager->getDefinition('entity_legal_document_version');
$updateManager->updateEntityType($entityType);
// Make sure we run this update only once.
$state->set('entity_legal.update_9002', TRUE);
}
return 9001;
}
/**
* Convert document version ID from string to serial.
*
* Changing the entity type ID field is painful, and it could not be achieved by
* using the entity definition update manager service in every case. It's
* necessary to perform raw SQL operations against the database. Note: this
* update path hasn't been tested on databases other than MySQL and PostgreSQL.
*/
function entity_legal_update_9002(): string {
$db = Database::getConnection();
if (!in_array($db->driver(), ['mysql', 'pgsql'], TRUE)) {
\Drupal::messenger()->addWarning(__FUNCTION__ . "() was tested only with the MySQL and PostgreSQL drivers but the current database driver is '{$db->driver()}'. Use it on your own risk");
}
$schema = $db->schema();
$updateManager = \Drupal::entityDefinitionUpdateManager();
$entityTypeManager = \Drupal::entityTypeManager();
// Don't use cached definitions.
$entityTypeManager->useCaches();
$fieldTables = [];
foreach (['entity_legal_document_version', 'entity_legal_document_acceptance'] as $entityTypeId) {
/** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $storage */
$storage = $entityTypeManager->getStorage($entityTypeId);
$tables = $storage->getTableMapping()->getTableNames();
foreach ($tables as $table) {
// Collect 'entity_legal_document_version' field dedicated table names.
if ($entityTypeId === 'entity_legal_document_version' && str_starts_with($table, 'entity_legal_document_version__')) {
$fieldTables[] = $table;
}
}
}
// PostgreSQL doesn't support UNSIGNED as cast type and SUBSTRING_INDEX().
$subString = $db->driver() === 'pgsql' ? "CAST(REVERSE(SPLIT_PART(REVERSE(%s), '_', 1)) AS INTEGER)" : "CAST(SUBSTRING_INDEX(%s, '_', -1) AS UNSIGNED)";
// Update content tables.
$schema->dropPrimaryKey('entity_legal_document_version');
$schema->addField('entity_legal_document_version', 'vid', [
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
], ['primary key' => ['vid']]);
$db->query("UPDATE {entity_legal_document_version} SET vid = " . sprintf($subString, 'name'));
$schema->dropField('entity_legal_document_version', 'name');
$schema->dropPrimaryKey('entity_legal_document_version_data');
$schema->dropIndex('entity_legal_document_version_data', 'entity_legal_document_version__id__default_langcode__langcode');
$db->query("UPDATE {entity_legal_document_version_data} SET vid = " . sprintf($subString, 'name'));
$schema->addPrimaryKey('entity_legal_document_version_data', [
'vid',
'langcode',
]);
$schema->addIndex('entity_legal_document_version_data', 'entity_legal_document_version__id__default_langcode__langcode', [
'vid',
'default_langcode',
'langcode',
],
[
'fields' => [
'vid' => [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
],
'default_langcode' => [
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
],
'langcode' => [
'type' => 'varchar_ascii',
'length' => 12,
'not null' => TRUE,
],
],
'indexes' => [
'entity_legal_document_version__id__default_langcode__langcode' => [
'vid',
'default_langcode',
'langcode',
],
],
]);
foreach ($fieldTables as $table) {
$schema->dropPrimaryKey($table);
$schema->dropIndex($table, 'revision_id');
$db->query("UPDATE {{$table}} SET entity_id = " . sprintf($subString, 'entity_id') . ", revision_id = " . sprintf($subString, 'revision_id'));
$schema->changeField($table, 'entity_id', 'entity_id', [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
], ['primary key' => ['entity_id', 'deleted', 'delta', 'langcode']]);
$schema->changeField($table, 'revision_id', 'revision_id', [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
]);
$schema->addIndex($table, 'revision_id', ['revision_id'], [
'fields' => [
'revision_id' => [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
],
],
'indexes' => ['revision_id' => ['revision_id']],
]);
}
$schema->addField('entity_legal_document_acceptance', 'vid', [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => FALSE,
]);
$db->query("UPDATE {entity_legal_document_acceptance} SET vid = " . sprintf($subString, 'document_version_name'));
$schema->changeField('entity_legal_document_acceptance', 'vid', 'vid', [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
]);
$schema->dropField('entity_legal_document_acceptance', 'document_version_name');
$schema->addIndex('entity_legal_document_acceptance', 'entity_legal_document_acceptance__cad57f4c0e', [
'vid',
],
[
'fields' => [
'vid' => [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
],
],
'indexes' => [
'entity_legal_document_acceptance__cad57f4c0e' => ['vid'],
],
]);
// Update field storage definitions.
$legacyIdDefinition = $updateManager->getFieldStorageDefinition('name', 'entity_legal_document_version');
$updateManager->uninstallFieldStorageDefinition($legacyIdDefinition);
$fieldDefinitions = unserialize(
$db->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.definitions.installed')
->condition('name', 'entity_legal_document_acceptance.field_storage_definitions')
->execute()
->fetchField()
);
unset($fieldDefinitions['document_version_name']);
$fieldDefinitions['vid'] = BaseFieldDefinition::create('entity_reference')
->setName('vid')
->setLabel(t('Document version'))
->setDescription(t('The document version this acceptance is bound to.'))
->setSetting('target_type', 'entity_legal_document_version')
->setTargetEntityTypeId('entity_legal_document_acceptance')
->setRequired(TRUE)
->setProvider('entity_legal');
$db->update('key_value')
->fields(['value' => serialize($fieldDefinitions)])
->condition('collection', 'entity.definitions.installed')
->condition('name', 'entity_legal_document_acceptance.field_storage_definitions')
->execute();
$schema = unserialize($db->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_version.entity_schema_data')
->execute()
->fetchField());
$schema['entity_legal_document_version']['primary key'] = ['vid'];
$schema['entity_legal_document_version_data']['primary key'] = [
'vid',
'langcode',
];
$schema['entity_legal_document_version_data']['indexes']['entity_legal_document_version__id__default_langcode__langcode'] = [
'vid',
'default_langcode',
'langcode',
];
$db->update('key_value')
->fields(['value' => serialize($schema)])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_version.entity_schema_data')
->execute();
$schema = unserialize($db->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_version.field_schema_data.vid')
->execute()
->fetchField());
$schema['entity_legal_document_version']['fields'] = [
'vid' => [
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
'size' => 'normal',
],
];
$schema['entity_legal_document_version_data']['fields'] = [
'vid' => [
'type' => 'int',
'size' => 'normal',
'unsigned' => TRUE,
'not null' => TRUE,
],
];
$db->update('key_value')
->fields(['value' => serialize($schema)])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_version.field_schema_data.vid')
->execute();
$schema = unserialize($db->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_version.field_schema_data.entity_legal_document_text')
->execute()
->fetchField());
foreach ($fieldTables as $table) {
$schema[$table]['fields']['entity_id'] = [
'description' => 'The entity id this data is attached to',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
];
$schema[$table]['fields']['revision_id'] = [
'description' => 'The entity revision id this data is attached to, which for an unversioned entity type is the same as the entity id',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
];
}
$db->update('key_value')
->fields(['value' => serialize($schema)])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_version.field_schema_data.entity_legal_document_text')
->execute();
$schema = unserialize($db->select('key_value')
->fields('key_value', ['value'])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_acceptance.field_schema_data.document_version_name')
->execute()
->fetchField());
$schema['entity_legal_document_acceptance']['fields'] = [
'vid' => [
'description' => 'The ID of the target entity.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
],
];
$schema['entity_legal_document_acceptance']['indexes'] = [
'entity_legal_document_acceptance__cad57f4c0e' => ['vid'],
];
$db->update('key_value')
->fields([
'name' => 'entity_legal_document_acceptance.field_schema_data.vid',
'value' => serialize($schema),
])
->condition('collection', 'entity.storage_schema.sql')
->condition('name', 'entity_legal_document_acceptance.field_schema_data.document_version_name')
->execute();
return "Document version entity IDs were converted from strings to auto-increment integers. Old IDs were converted by retaining the numeric part (former timestamp) as new integer ID. For instance, 'legal_notice_1683794048' (string) was converted into 1683794048 (int).";
}
