0

On a paragraph type, I have a field I want to migrate to a new field of type "list_string". To do that in the deployment and like our automatic deployment begin by an update of the database follow by importation of configurations, I want to create the new field programmatically before to do the migration in another hook_update.

I'm using the example of this article https://www.metaltoad.com/blog/programmatically-importing-drupal-8-field-configurations which is perfect except I have a problem because my new field is of type list_string. My configuration for field.storage is:

langcode: fr
status: true
dependencies:
  module:
    - options
    - paragraphs
id: paragraph.field_types_link
field_name: field_types_link
entity_type: paragraph
type: list_string
settings:
  allowed_values:
    -
      value: anchor
      label: Ancre
    -
      value: internal
      label: Interne
    -
      value: external
      label: Externe
  allowed_values_function: ''
module: options
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

When I create my new field based on my configuration file like that:

$field_storage_link = \Drupal::service('config.storage.sync')->read('field.storage.paragraph.field_types_link');

\Drupal::entityTypeManager()->getStorage('field_storage_config')
  ->create($field_storage_link)
  ->save();

I have this error.

[error] The configuration property settings.allowed_values.0.label.0 doesn't exist.

If I remove the list of allowed_values, it works and I can add my field to paragraphes bundles but in this case, I'm not able to do my migration properly because the allowed_values of my field are empty and I don't know how to update it programmatically. Someone can explain what's is the problem in my code and how to fix it?

2 Answers 2

2

I finish by find what was the problem. When I read the config file, my allowed value are of format:

[
  [
    'value' => 'anchor',
    'label' => 'Anchor'
  ],
  [
    'value' => 'internal',
    'label' => 'Internal'
  ],
  [
    'value' => 'external',
    'label' => 'External'
  ]
]

But the FieldStorageConfig wait a format:

[
  'anchor' => 'Anchor',
  'internal' => 'Internal',
  'external' => 'External'
]

So I add a transformation before to save my new field:

$field_storage_link = \Drupal::service('config.storage.sync')->read('field.storage.paragraph.field_types_link');

$allowed_values_link = [];

foreach($field_storage_link['settings']['allowed_values'] as $value) {
  $allowed_values_link[$value['value']] = $value['label'];
}

$field_storage_link['settings']['allowed_values'] = $allowed_values_link;

\Drupal::entityTypeManager()->getStorage('field_storage_config')
      ->create($field_storage_link)
      ->save();

$field_type_link = \Drupal::service('config.storage.sync')->read('field.field.paragraph.link_tdm.field_types_link');

\Drupal::entityTypeManager()->getStorage('field_config')->create($field_type_link)->save();

It works properly.

0

For others with the same issue, see this important comment by Berdir at https://www.drupal.org/project/drupal/issues/2944144#comment-12481021 saying:

That's not the correct way to create a config entity from config. Here's a snippet based on what I did just today:

  $module_handler = \Drupal::moduleHandler();
  $config_storage = new FileStorage($module_handler->getModule('yourmodule')->getPath() . '/config/install');

  foreach (['field.storage.user.field_name', 'field.field.user.user.field_name'] as $config_name) {
    $config_record = $config_storage->read($config_name);

    $entity_type = \Drupal::service('config.manager')->getEntityTypeIdByName($config_name);
    /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage($entity_type);
    $entity = $storage->createFromStorageRecord($config_record);
    $entity->save();
  }

The important part is "$entity = $storage->createFromStorageRecord($config_record);", the config structure and config entity structure doesn't always match 1:1.

I can confirm this solved the problem for me with the same error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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