2

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.

1

I was having the exact same issue, trying to update the "max_length" of the name field of a custom entity. I did a hook_update like that :

function mymodule_update_8005() {
  $entity_definition_update_manager = \Drupal::service('entity.definition_update_manager');
  $field_definition = $entity_definition_update_manager->getFieldStorageDefinition('name', 'myentityid');
  $field_definition->setSetting('max_length', 255);
  $entity_definition_update_manager->updateFieldStorageDefinition($field_definition);
}

But then, even if the fieldDefinition had correctly changed, I was still having the old length limitation.

Finally, what I had forgotten to do was changing this max_length in my entity definition itself, here :

public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
  $fields['name'] = BaseFieldDefinition::create('string')
  ->setLabel(t('Title'))
  ->setSettings(array(
    'max_length' => 255,
    'text_processing' => 0,
  ));
  ...

After that, it worked as desired.

  • Sadly, this doesn't work for me. I updated my setting in both places, but DB field property is still the same. – Miloš Kroulík Dec 18 '17 at 21:55
  • I've also tried drush updatedb --entity-updates -y but order of updates is wrong, so it fails. – Miloš Kroulík Dec 18 '17 at 22:07
  • This did work for me, after running the drush command above – ben.hamelin Feb 22 '18 at 16:57
1

In latest version of Drupal seems to work only reinstall option, so basic flow is:

$entityUpdateManager = \Drupal::entityDefinitionUpdateManager();
  $field_definition = $entityUpdateManager->getFieldStorageDefinition($fieldName, $entityTypeId);
  $entityUpdateManager->uninstallFieldStorageDefinition($field_definition);
  $newStorageDefinition = BaseFieldDefinition::create('string')
    ->setLabel(t('Label'))
    ->setSetting('max_length', 191)
    ->setDescription(t('Description.'))
    ->setDisplayConfigurable('form', TRUE)
    ->setDisplayConfigurable('view', TRUE); // Same as in entity type class.
  $entityUpdateManager->installFieldStorageDefinition(
    $fieldName, $entityTypeId, $moduleName, $newStorageDefinition
  );
  • Do you know of any reference/docs about this? The prior answer from 2017 doesn't work, and with no 'drush entity-updates' this is getting too confusing to have no documentation. – Dylan Sep 25 at 0:32
  • Basic info is drupal.org/node/3034742 But I tried out some variants to find working. – Olexyy Osadchyy Sep 26 at 6:11
  • This worked for me, but it obviously removes all the data also, which isn't ideal. – Dylan Sep 27 at 19:59
  • Yes uninstall, removes, so temporary field (property) may be solution. – Olexyy Osadchyy Sep 28 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.