2

I have a custom field type. Now I need to add an additional property to it.

I added the new property to propertyDefinitions() and schema() methods.

What should I do in the update hook? The field type is already in use, and fields have values stored in the database.

3

I ended up using the following code.

function my_module_update_8001() {
  $field_type = 'my_field_type';
  $new_property = 'my_new_property';

  $manager = \Drupal::entityDefinitionUpdateManager();
  $field_map = \Drupal::entityManager()->getFieldMapByFieldType($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 \Drupal\Core\Entity\Sql\SqlContentEntityStorage) {
        $table_mapping = $storage->getTableMapping([
          // We pass only one storage definition to make
          // \Drupal\Core\Entity\Sql\DefaultTableMapping::getDedicatedTableNames()
          // return only tables we need.
          $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();
          \Drupal::database()
            ->schema()
            ->addField($table_name, $columns[$new_property], $field_schema['columns'][$new_property]);
        }
      }
      $manager->updateFieldStorageDefinition($field_storage_definition);
    }
  }
}
  • I could not thank you more! I changed the code slightly to prevent the exceptions – Alex Aug 3 '16 at 9:49
  • what would be the opposite? To remove fields? – Alex Aug 3 '16 at 9:51
0

Based on Leksats answer I added a few lines to prevent some possible exceptions...

  $field_type = 'fieldtype';
  $new_property = 'newproperty';

  $manager = \Drupal::entityDefinitionUpdateManager();
  $field_map = \Drupal::entityManager()->getFieldMapByFieldType($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 \Drupal\Core\Entity\Sql\SqlContentEntityStorage) {
        $table_mapping = $storage->getTableMapping([
          // We pass only one storage definition to make
          // \Drupal\Core\Entity\Sql\DefaultTableMapping::getDedicatedTableNames()
          // return only tables we need.
          $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 = $schema->fieldExists($table_name, $columns[$new_property]);
          $table_exists = $schema->tableExists($table_name);

          if (!$fieldExists && $tableExists) {
            $schema->addField($table_name, $columns[$new_property], $field_schema['columns'][$new_property]);
          }
        }
      }
      $manager->updateFieldStorageDefinition($field_storage_definition);
    }
  }
0

Based on Alex' answer, I updated the code with non-deprecated code (entity_field.manager). Also fixed two small variable mistakes. This piece of code can be added to .install files for example and will update all entities containing the field you'd like to update.

$field_type = 'fieldtype_to_be_updated';
$new_property = 'new_property_to_be_added';

$manager = \Drupal::entityDefinitionUpdateManager();
$field_map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType($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 \Drupal\Core\Entity\Sql\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 = $schema->fieldExists($table_name, $columns[$new_property]);
        $table_exists = $schema->tableExists($table_name);

        if (!$field_exists && $table_exists) {
          $schema->addField($table_name, $columns[$new_property], $field_schema['columns'][$new_property]);
        }
      }
    }
    $manager->updateFieldStorageDefinition($field_storage_definition);
  }
}

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.