Unable to programmatically add a list_integer field to field storage. It throws the following error

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

When trying to parse a field storage yml config file and add field storage in an update hook, it fails. The field storage yml is taken directly from the configuration synchronization exporter w/out the UUID and core default_config_hash keys and values.

use Symfony\Component\Yaml\Yaml;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;

function my_module_update_8001() {
  $module_path = drupal_get_path('module', 'my_module');

  // Add the new field storage and instance configuration.
  $yml = Yaml::parse(file_get_contents($module_path . '/config/install/field.storage.node.field_list_integer.yml'));
  if (!FieldStorageConfig::loadByName($yml['entity_type'], $yml['field_name'])) {
    FieldStorageConfig::create($yml)->save();
  }
  $yml = Yaml::parse(file_get_contents($module_path . '/config/install/field.field.node.article.field_list_integer.yml'));
  if (!FieldConfig::loadByName($yml['entity_type'], $yml['bundle'], $yml['field_name'])) {
    FieldConfig::create($yml)->save();
  }
}

field.storage.node.field_list_integer.yml

langcode: en
status: true
dependencies:
  module:
    - node
    - options
id: node.field_list_integer
field_name: field_list_integer
entity_type: node
type: list_integer
settings:
  allowed_values:
    -
      value: 0
      label: Option A
    -
      value: 1
      label: Option B
  allowed_values_function: ''
module: options
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

Comments

jasonawant created an issue. See original summary.

Berdir’s picture

Category: Bug report » Support request
Status: Active » Fixed

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.