Re-importing the configuration of filed_storage_config is impossible when field have a list of allowed_values. An illustrative example: http://cgit.drupalcode.org/config_devel/tree/src/EventSubscriber/ConfigD...

Steps to reproduce:

  • Create field storage configuration and save it.
  • Read the configuration by name from storage.
  • Create a duplicate, set the same UUID to update existing.
  • Save the configuration.

Comments

BR0kEN created an issue. See original summary.

br0ken’s picture

Status: Active » Needs review
StatusFileSize
new1.53 KB

Let's start from tests, which should fail.

Status: Needs review » Needs work

The last submitted patch, 2: core-reimport_allowed_values-2802379-2.patch, failed testing.

br0ken’s picture

Status: Needs work » Needs review
StatusFileSize
new3.08 KB
new1.41 KB

Possible fix.

valthebald’s picture

Issue tags: +Needs tests

Needs tests, if this is a new bug

br0ken’s picture

valthebald’s picture

Issue tags: -Needs tests

Sorry, missed that the patch already contains a test

gaydamaka’s picture

Status: Needs review » Reviewed & tested by the community

Patch #4 solve the issue with re-importing option field with a list of allowed values.

br0ken’s picture

Assigned: Unassigned » br0ken
Status: Reviewed & tested by the community » Needs work

When the field already in use and has a set of allowed values then reimporting will lead to fail inside of options_field_storage_config_update_forbid() function because structures of compared items could differ. For instance:

/var/www/docroot/core/modules/field/src/Entity/FieldStorageConfig.php:265:
array(2) {
  'allowed_values' =>
  array(3) {
    [0] =>
    array(2) {
      'value' =>
      string(3) "red"
      'label' =>
      string(3) "Red"
    }
    [1] =>
    array(2) {
      'value' =>
      string(4) "navy"
      'label' =>
      string(4) "Navy"
    }
    [2] =>
    array(2) {
      'value' =>
      string(5) "white"
      'label' =>
      string(5) "White"
    }
  }
  'allowed_values_function' =>
  string(0) ""
}
/var/www/docroot/core/modules/field/src/Entity/FieldStorageConfig.php:265:
array(2) {
  'allowed_values' =>
  array(3) {
    'red' =>
    string(3) "Red"
    'navy' =>
    string(4) "Navy"
    'white' =>
    string(5) "White"
  }
  'allowed_values_function' =>
  string(0) ""
}
br0ken’s picture

Assigned: br0ken » Unassigned
Status: Needs work » Needs review
StatusFileSize
new5.49 KB
new2.85 KB

Status: Needs review » Needs work

The last submitted patch, 10: core-reimport_allowed_values-2802379-10.patch, failed testing.

br0ken’s picture

Status: Needs work » Needs review
StatusFileSize
new1.3 KB
new5.74 KB

The last submitted patch, 10: core-reimport_allowed_values-2802379-10.patch, failed testing.

br0ken’s picture

Issue tags: +Dublin2016
gaydamaka’s picture

Status: Needs review » Reviewed & tested by the community

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 12: core-reimport_allowed_values-2802379-11.patch, failed testing.

br0ken’s picture

Status: Needs work » Reviewed & tested by the community

Back RTBC since tests were passed.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/field/src/Entity/FieldStorageConfig.php
    @@ -7,6 +7,7 @@
    +use Drupal\Core\Field\FieldItemInterface;
    

    This is not actually used in code.

  2. +++ b/core/modules/field/src/Entity/FieldStorageConfig.php
    @@ -368,6 +369,11 @@ protected function preSaveUpdated(EntityStorageInterface $storage) {
    +    $this->settings = $field_item_class::storageSettingsToConfigData($this->settings);
    +    $this->settings = $field_item_class::storageSettingsFromConfigData($this->settings);
    

    This looks super weird.

  3. +++ b/core/modules/field/src/Entity/FieldStorageConfig.php
    @@ -776,6 +782,9 @@ public function getUniqueStorageIdentifier() {
    +   * @return FieldItemInterface
    +   *   An instance of field item.
    

    This should be a fully qualified class name.

  4. +++ b/core/modules/options/tests/src/Kernel/OptionsFieldTest.php
    @@ -97,4 +90,59 @@ function testUpdateAllowedValues() {
    +    $field_storage_config = $this->container->get('config.storage')
    ...
    +    FieldStorageConfig::create($field_storage_config)
    

    The expectation that array passed to create and the stored array in configuration is the same is the problem here. I can see why it exists and it seems sensible but it's not the current behaviour - which we still need to support - otherwise this is an API change.

br0ken’s picture

  1. It's used, but if do what you mentioned in #3, then yes, it will not be needed.
  2. Weird for me - is even presence of these methods (storageSettingsToConfigData, storageSettingsFromConfigData etc.)
  3. Why? I didn't know about that. Is Drupal.org PHPDoc parser does not support use statements?
  4. I am sorry, but I did not understood what you've tried to say. Could you please explain a bit?
br0ken’s picture

Issue tags: -Dublin2016
br0ken’s picture

@alexpott, please, take some time on this.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

dangur’s picture

Status: Needs work » Needs review
StatusFileSize
new738 bytes

PHPUnit tests are failing with

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

when I attempt to add additional fields to a custom entity that has list values. The issue seems similar enough to this one to add it here instead of making a new issue. Test passes with this patch.

Status: Needs review » Needs work

The last submitted patch, 24: core-reimport-allowed-values-2802379-24.patch, failed testing. View results

alexpott’s picture

Re #19 1 and 3 - @BR0kEN our code standards are for fully qualified classnames. And no we don't support use statements just for stuff in documentation.

Re #19 2 - The reason for storageSettingsToConfigData and storageSettingsFromConfigData is because the structure of the options allowed values at runtime can not be stored in YAML files without corruption so we need to change it. YAML is specific about what can go into keys.

Re #19 4 - this is kinda the same as point 2. The values in config don't map exactly to the values on the entity. The assumption that you can read values from configuration and use them to create an entity is not correct.

+++ b/core/modules/options/tests/src/Kernel/OptionsFieldTest.php
@@ -15,16 +15,9 @@
   /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('options');
-
-  /**
    * Test that allowed values can be updated.
    */
-  function testUpdateAllowedValues() {
+  public function testUpdateAllowedValues() {

These are unrelated changes not necessary to fix the bug.

br0ken’s picture

Status: Needs work » Needs review
StatusFileSize
new4.14 KB

Re-roll for 8.5.x.

br0ken’s picture

StatusFileSize
new2.1 KB

Let's try with tests only.

Status: Needs review » Needs work

The last submitted patch, 28: 2802379-28.patch, failed testing. View results

br0ken’s picture

Status: Needs work » Needs review

As expected.

lpeabody’s picture

Status: Needs review » Reviewed & tested by the community

I can confirm this is a bug, and it becomes especially prevalent when using a Features configuration management strategy. Reverting a field storage object for a list field results in this error. I've applied the patch in #27 and the revert works as expected.

Reviewed against core 8.3.7.

br0ken’s picture

@alexpott #18.2, regarding super weird lines: $this->settings before the processing have the following structure:

array(2) {
  ["allowed_values"]=>
  array(3) {
    [0]=>
    array(2) {
      ["value"]=>
      int(1)
      ["label"]=>
      string(3) "One"
    }
    [1]=>
    array(2) {
      ["value"]=>
      int(2)
      ["label"]=>
      string(3) "Two"
    }
    [2]=>
    array(2) {
      ["value"]=>
      int(3)
      ["label"]=>
      string(5) "Three"
    }
  }
  ["allowed_values_function"]=>
  string(0) ""
}

The $field_item_class::storageSettingsToConfigData() and $field_item_class::storageSettingsFromConfigData() helps to restructure settings into a correct format:

array(2) {
  ["allowed_values"]=>
  array(3) {
    [1]=>
    string(3) "One"
    [2]=>
    string(3) "Two"
    [3]=>
    string(5) "Three"
  }
  ["allowed_values_function"]=>
  string(0) ""
}

An underlying issue is, probably, somewhere deeper but the patch is still working.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/options/tests/src/Kernel/OptionsFieldTest.php
@@ -97,4 +97,59 @@ public function testUpdateAllowedValues() {
+    FieldStorageConfig::create($field_storage_config)
+      ->set('uuid', $this->fieldStorage->uuid())
+      ->enforceIsNew(FALSE)
+      ->save();

This is not how it is supposed to be done. There is a method on the storage called createFromStorageRecord and guessing by #31 features is not using it.

br0ken’s picture

Using the createFromStorageRecord() or updateFromStorageRecord() I couldn't confirm the problem. Probably it's exists before 8.5.x. Needs more investigations.

br0ken’s picture

Status: Needs work » Closed (outdated)

After checking latest codebases at 8.3.x, 8.4.x and 8.5.x I wasn't able to reproduce the behavior.

jasonawant’s picture