Skip to content

Instantly share code, notes, and snippets.

@fredysan
Last active June 14, 2024 07:18
Show Gist options
  • Save fredysan/5a9283cdfe4eef5081a15ff47d2d60f6 to your computer and use it in GitHub Desktop.
Save fredysan/5a9283cdfe4eef5081a15ff47d2d60f6 to your computer and use it in GitHub Desktop.
How to add a property to an existing field in Drupal 8/9

How to add a property to an existing Field Type in Drupal 8/9

  • Modify the schema definition of your custom field type to add a new column.
  • Adjust the AddFieldProperty class to fit your needs.
  • Inside a hook_update_N() function run the execute function.
<?php
namespace Drupal\my_module;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
/**
* Adds a new property to an existing field type.
*
* @see: Drupal\my_module\Plugin\FieldType\CustomFieldType.php
*/
class AddFieldProperty {
protected $entity_type_id = 'entity';
protected $field_name = 'field';
protected $property = 'property';
/**
* Builds the response.
*/
public function execute() {
$manager = \Drupal::entityDefinitionUpdateManager();
$new_field_definition = BaseFieldDefinition::create('custom_field_type')
->setLabel(t('Label'))
->setDescription(t('Description'))
->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'custom_field_type_formatter',
])
->setDisplayOptions('form', [
'label' => 'above',
'type' => 'custom_field_type_widget',
])
->setDisplayConfigurable('view', TRUE)
->setDisplayConfigurable('form', TRUE);
// Overrides the current field definition.
$manager->installFieldStorageDefinition($this->field_name, $this->entity_type_id, $this->entity_type_id, $new_field_definition);
// Add the column for the new property in each of the field tables.
$field_map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('custom_field_type');
foreach ($field_map as $entity_type_id => $fields) {
foreach (array_keys($fields) as $field_name) {
$field_storage_definition = $manager->getFieldStorageDefinition($field_name, $entity_type_id);
$storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);
if ($storage instanceof SqlContentEntityStorage) {
$table_mapping = $storage->getTableMapping([
$field_name => $field_storage_definition,
]);
$table_names = $table_mapping->getDedicatedTableNames();
$columns = $table_mapping->getColumnNames($field_name);
foreach ($table_names as $table_name) {
$field_schema = $field_storage_definition->getSchema();
$schema = \Drupal::database()->schema();
$field_exists = isset($columns[$this->property]) && $schema->fieldExists($table_name, $columns[$this->property]);
$table_exists = $schema->tableExists($table_name);
if (!$field_exists && $table_exists) {
$schema->addField($table_name, $columns[$this->property], $field_schema['columns'][$this->property]);
}
}
}
$manager->updateFieldStorageDefinition($field_storage_definition);
}
}
$database = \Drupal::database();
$manager = \Drupal::entityDefinitionUpdateManager();
$field_storage_definition = $manager->getFieldStorageDefinition($this->field_name, $this->entity_type_id);
$entity_storage = \Drupal::entityTypeManager()->getStorage($this->entity_type_id);
$table_mapping = $entity_storage->getTableMapping([
$this->field_name => $field_storage_definition,
]);
$table_names = $table_mapping->getDedicatedTableNames();
foreach ($table_names as $table_name) {
// Store the existing values.
$table_values = $database->select($table_name)
->fields($table_name, [
'bundle',
'entity_id',
'revision_id',
'delta',
])
->execute()
->fetchAll();
foreach ($table_values as $row) {
$property_value = 'SOMETHING HERE';
// Update existing data.
$result = $database->update($table_name)
->fields([
$this->field_name . '_' . $this->property => $property_value,
])
->condition('deleted', $row['deleted'])
->condition('entity_id', $row['entity_id'])
->condition('revision_id', $row['revision_id'])
->condition('langcode', $row['langcode'])
->condition('delta', $row['delta'])
->execute();
}
}
}
}
<?php
namespace Drupal\my_module\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
/**
* @FieldType(
* id = "custom_field_type",
* label = @Translation("Custom Field Type"),
* description = @Translation("Custom Field Type Description"),
* category = @Translation("Category"),
* default_widget = "custom_field_type_widget",
* default_formatter = "custom_field_type_formatter",
* )
*/
class CustomFieldType extends FieldItemBase {
/**
* {@inheritDoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return [
'columns' => [
'value' => [
'type' => 'varchar',
'length' => 2048,
],
# NEW PROPERTY
'property' => [
'type' => 'varchar',
'length' => 255,
],
],
];
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
return [
'value' => DataDefinition::create('string')->setLabel(t('Value')),
'property' => DataDefinition::create('string')->setLabel(t('Property')),
];
}
/**
* {@inheritdoc}
*/
public function isEmpty() {
$value1 = $this->get('value')->getValue();
$value2 = $this->get('property')->getValue();
return empty($value1) || empty($value2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment