I'm struggling with writing an update hook that will simply update the length of a text base field attached to an entity of mine.
Here's my update hook:
function my_module_update_8001() {
// Collect all existing story run data.
$database = \Drupal::database();
// Gather all the existing story run data.
$tables = [
'content_tile_field_data',
'content_tile_field_revision',
];
$existing_data = [];
foreach ($tables as $table) {
$existing_data[$table] = $database->select($table)
->fields($table)
->execute()
->fetchAll(PDO::FETCH_ASSOC);
$database->truncate($table)->execute();
}
// Update the "name" base field definition to a new max length
$update_manager = \Drupal::entityDefinitionUpdateManager();
$name_field = $update_manager->getFieldStorageDefinition('name', 'content_tile');
$name_field->setSetting('max_length', 100);
$update_manager->updateFieldStorageDefinition($name_field);
// Restore the data.
foreach ($tables as $table) {
$insert_query = $database
->insert($table)
->fields(array_keys(end($existing_data[$table])));
foreach ($existing_data[$table] as $row) {
$insert_query->values(array_values($row));
}
$insert_query->execute();
}
}
After running this, the name
field is clearly dropped and re-added (I know because it now appears at the end of the list of columns in the table), but the length is still set to 50, the old value.
I've narrowed this down to BaseFieldDefinition::getSchema():
public function getSchema() {
if (!isset($this->schema)) {
// Get the schema from the field item class.
$definition = \Drupal::service('plugin.manager.field.field_type')->getDefinition($this->getType());
$class = $definition['class'];
$schema = $class::schema($this);
// Fill in default values.
$schema += array(
'columns' => array(),
'unique keys' => array(),
'indexes' => array(),
'foreign keys' => array(),
);
// Merge custom indexes with those specified by the field type. Custom
// indexes prevail.
$schema['indexes'] = $this->indexes + $schema['indexes'];
$this->schema = $schema;
}
return $this->schema;
}
The schema definition is cached, so the update process gets the old schema data instead of regenerating it. There appears to be no way to clear this internal cache.
If I comment out the code related to the caching, it works as expected.
Is there another approach to this that I'm missing?
EDIT: The approach I took instead is to just load the current definition and pass that through to the update manager, like this:
$update_manager = \Drupal::entityDefinitionUpdateManager();
$definitions = \Drupal::entityManager()->getFieldStorageDefinitions('content_tile');
$name_field_definition = $definitions['name'];
$update_manager->updateFieldStorageDefinition($name_field_definition);
I guess this is not recommended normally, but it worked just fine.