Change or update the existing field length in Drupal 8

If you ever tried to change the node field storage settings on field that already contains data, you probably encountered the following message:

There is data for this field in the database. The field settings can no longer be changed.

Or tried to modify existing field programmatically and got the following exception:

Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException: The SQL storage cannot change the schema for an existing field (title in node entity) with data.

The reason being is that once data has been stored we can no longer guarantee that modifying field storage will not have any effect on our data integrity.

Increase node title length

This is all good, but let's assume that we know what we are doing and we want to increase the node field title length so users are able to enter titles that exceed 255 characters limited by database varchar 255 field to 500 characters.

Two steps are required: increase the length on the BaseFieldDefinition and increase the length on the schema (node_field_data and node_field_revision tables title column).

Change length on the node base field

Entity base field can be altered using the hook_entity_base_field_info_alter. This will allow users to enter 500 characters but we need also modify the schema, otherwise, data would get stripped back to 255 characters.

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;

function hook_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  /** @var \Drupal\Core\Field\BaseFieldDefinition $fields[] */
  if ($entity_type->id() === 'node' &&
    (isset($fields['title']) && $fields['title'] instanceof BaseFieldDefinition)) {
    $fields['title']->setSetting('max_length', 500);
  }
}

Change field length schema using hook_update_N

We are going to use update hook to modify the schema. If you are using this as a feature it could also be placed in the hook_install to apply this once the module gets enabled. If that's the case, don't forget to use the hook_uninstall to set the length back.

function hook_update_N() {
  $field_spec = [
    'type' => 'varchar',
    'length' => '500',
    'not null' => TRUE,
  ];
  \Drupal::database()->schema()->changeField('node_field_data','title', 'title', $field_spec);
  \Drupal::database()->schema()->changeField('node_field_revision','title', 'title', $field_spec);

  // Here we copy base field definition from node entity class,
  // modify it according to our needs and reinstall
  // modified field definition.
    $definition = BaseFieldDefinition::create('string')
    ->setLabel(t('Name'))
    ->setRequired(TRUE)
    ->setTranslatable(TRUE)
    ->setRevisionable(TRUE)
    ->setDefaultValue('')
    ->setSetting('max_length', 500)
    ->setDisplayOptions('form', [
      'type' => 'string_textfield',
      'weight' => -5,
    ])
    ->setDisplayConfigurable('form', TRUE)
    ->setDisplayConfigurable('view', TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('title', 'node', 'node', $definition);
}

Final step

Run the update hook and clear your cache.

Image

Fixing the mismatched entity and/or the field definition

After all is set and done, there is also the following message that you may encounter, if we would skip any of those steps above:

Mismatched entity and/or field definitions
The following changes were detected in the entity type and field > definitions.
Node - The Title field needs to be updated.

This message indicates that we have a mismatch between entity schema and field definition. The following guide can be a reference which steps we need to check in order to fix the mentioned issue.

Entity field definition storage
We can investigate how current mismatched field serialized schema looks like by looking into the key_value table (collection=entity.storage_schema.sql).

SELECT value FROM key_value 
WHERE 
  collection='entity.storage_schema.sql' AND name='node.field_schema_data.title';

Or by using entity_field.manager service to get back the Drupal\Core\Field\BaseFieldDefinition object:

// Get field storage definition
$definition = \Drupal::service('entity_field.manager')->getFieldStorageDefinitions('node')['title'];
// Get field definition
$definition = \Drupal::service('entity_field.manager')->getFieldDefinitions('node')['title'];

 

Add new comment

CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.