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.
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