Problem/Motivation

When a data type definition is built by combing two other definition (a data type definition with a sub definition) in \Drupal\Core\Config\TypedConfigManager::getDefinitionWithReplacement() the sub definition doesn't get fully built by looping through its parent definitions, so the resulting merged definition is incomplete.

I noticed this when the resulting merged definition did not inherit any of the mappings provided by the sub definition.

Proposed resolution

Loop through the parent definition types of the sub definition with \Drupal\Core\Config\TypedConfigManager::getDefinition() before merging.

Remaining tasks

  • Test to show failing
  • Patch to fix

Non blocking: #2755825: Add tests for 3 dynamic merges to verify dynamic data types dependencies lead to complete definitions

User interface changes

NA

API changes

NA

Data model changes

NA (there is but now it will be what we thought it should be)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yanniboi created an issue. See original summary.

yanniboi’s picture

This patch is the start of a test to show the problem, although I have not got any tests failing yet.

This can easily be added to an existing test module rather than creating a new one, but I wasn't sure which so I am open to suggestions.

yanniboi’s picture

Ok, so I have noticed that there is already a good test to build on rather than writing my own...
Disregard the first patch.

I have added a test to show that there is a problem in core.

Basically, I am saving a config object that should build its data definition from 2 definitions ('wrapping.test.other_double_brackets.*' and 'test.double_brackets.cat:*.*') and showing that there is a problem when there is missing schema for a mapping on 'test.double_brackets.cat:*.*' (ie. 'breed').

This is to illustrate that when 2 data definitions are merged as part of TypedConfigManager::getDefinitionWithReplacement() the second definition (referenced in code as $sub_type) isn't a fully built data definition because none of its information is inherited from parent definitions.

yanniboi’s picture

Here is my solution, to fully build the data definition of the $sub_type definition before merging it.

yanniboi’s picture

For clarity, looking at the rest of TypedConfigManager::getDefinitionWithReplacements() helps a lot because the pattern that I have implemented in my patch is used quite a lot:

<?php
      $merge = $this->getDefinition($definition['type'], $exception_on_invalid);
      // Preserve integer keys on merge, so sequence item types can override
      // parent settings as opposed to adding unused second, third, etc. items.
      $definition = NestedArray::mergeDeepArray(array($merge, $definition), TRUE);
?>
yanniboi’s picture

Issue summary: View changes

The last submitted patch, 3: merging_data_types-2693081-3.patch, failed testing.

yanniboi’s picture

FileSize
1.29 KB
3.62 KB

I just realised that the sub definition may not have type set and may not need looping over in some cases.

Patch to fix and interdiff...

yanniboi’s picture

Status: Needs review » Needs work

Looks like core/modules/config/src/Tests/ConfigSchemaTest.php has moved or been deleted... I will have a look at that and rebase.

yanniboi’s picture

Status: Needs work » Needs review
FileSize
3.67 KB

Ok, I've (sorta) rebased my patch. ConfigSchemaTest moved to being a phpunit Kernel test.

yanniboi’s picture

YesCT’s picture

Issue summary: View changes
Status: Needs review » Needs work
  1. +++ b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml
    @@ -270,3 +270,30 @@ test.double_brackets.turtle.horse:
    +test.double_brackets.cat:*.*:
    
    +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
    @@ -631,6 +631,24 @@ public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
    +          'id' => 'cat:persion.dog',
    

    why the colon in the id? is that what indicates an inheritance? ... or is the colon just part of an arbitrary string, and not syntactically significant (maybe it is a convention used in panels id strings and so used here in a similar use case example to match something practical that people might use).

  2. what gets lost in the inheritance (merge) the child stuff or the parent stuff?

    webflow says: I guess it is because we didn't fully resolve the parent dynamic type, so the parent property was missing?

    (in the current test, without the fix, the config gets either 1 or 3 properties.. I wonder if we could count the properties in the assert, nah, probably better to assert the expected ones are there with the values than to just count them)

    maybe that means what is missing is the parent stuff, in this case the breed.

    wait...

    +++ b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml
    @@ -270,3 +270,30 @@ test.double_brackets.turtle.horse:
    +test.double_brackets.breed:
    +  type: test.double_brackets
    +  mapping:
    +    breed:
    +      type: string
    

    test.double_brackets.breeed "extends" test.double_brackets

    so like php classes and extending, breed is a property from a "subclass". so... id, foo, and bar are parent properties, and breed is a child property?

    ??? (trying to use the vocabulary to understand what the words in the issue mean, and how we can document what this is doing)

    maybe re-reading http://hojtsy.hu/blog/2014-dec-12/drupal-8-configuration-schema-cheat-sheet would help.

  3. +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
    +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
    @@ -631,6 +631,24 @@ public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
    
    @@ -631,6 +631,24 @@ public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
    +    \Drupal::configFactory()->getEditable('wrapping.config_schema_test.other_double_brackets')
    +      ->setData($typed_values)
    +      ->save();
    +    $tests = \Drupal::service('config.typed')->get('wrapping.config_schema_test.other_double_brackets')->get('tests')->getElements();
    +    $definition = $tests[0]->getDataDefinition()->toArray();
    +    $this->assertEqual($definition['type'], 'wrapping.test.other_double_brackets.*||test.double_brackets.cat:*.*');
    

    the test fails nicely on the ->save() because it can't save data for a property (?) that is missing from the bad merge.

    it would be extra good to also assert the properties are there, and have the values expected in an actual assert.

  4. This test has many levels of inheritance, and two of them are dynamic. I wonder if this will work for any number of dynamic things in a chain (merge).

    Can answer this two ways probably, looking at the fix in context (to see where it is in loops), and a test that has 3 dynamic types would prove it would work for any number.

  5. I wonder if we can make this test more clear with some better names for things? ... or comments in the test or schema?
  6. +++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigSchemaTest.php
    @@ -631,6 +631,24 @@ public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
    +    $typed_values = [
    +      'tests' => [
    ...
    +    \Drupal::configFactory()->getEditable('wrapping.config_schema_test.other_double_brackets')
    

    I was wondering why the test did this in the code instead of a config yml file. I looked; the rest of ConfigSchemaTest follows that pattern. ok. :)

YesCT’s picture

Issue tags: +DevDaysMilan
yanniboi’s picture

The precise error that is thrown when this test runs without the merge fix is the following:

Drupal\Core\Config\Schema\SchemaIncompleteException: Schema errors for wrapping.config_schema_test.other_double_brackets with the following errors: wrapping.config_schema_test.other_double_brackets:tests.0.breed missing schema in Drupal\Core\Config\Testing\ConfigSchemaChecker->onConfigSave() (line 98 of /var/www/html/core/lib/Drupal/Core/Config/Testing/ConfigSchemaChecker.php). Drupal\Core\Config\Testing\ConfigSchemaChecker->onConfigSave(Object, 'config.save', Object) (Line: 116)

So this confirms that it is breed that is missing from the bad merge.

I like the idea of checking more that 2 dynamic types. Will have a look at that.

I have no idea how to simplify the language, but I am open to suggestions :)

yanniboi’s picture

Status: Needs work » Needs review
FileSize
950 bytes
3.88 KB

I've had another look at the test in the context of other schema definitions and tests in the config_schema_test and come to the following conclusions.

  1. I did not choose 'test.double_brackets.cat.dog', that was already part of an existing test.
  2. The use of schema properties 'foo' and 'bar' is required for the construction of 'wrapping.test.double_brackets.*' which is of type test.double_brackets.[foo].[bar] which evaluates to test.double_brackets.cat.dog
  3. I have added an assertion in the test to make sure that the definition for breed is contained in the merged definition on the off chance that the test ever does not throw an error while saving a config entity for which the schema is incomplete.

I was tempted to also test the config entity storage of foo and bar, etc. but I decided that because foo and bar are used in the evaluation of the config definition, there would be other errors if there was a problem with setting them to cat/dog as part of the merge.

YesCT’s picture

@yanniboi Thanks, that additional assert makes me feel like the test is more complete.

I triggered a test run on the patch on 8.1.x so we can see how it does there.

I think it would be good to get a test only patch (and have tests run on it against 8.1.x and 8.2.x).

I would be comfortable with making another issue to look into the 3 dynamic test case, cause I think thinking exactly what that would look like will be challenging and take time, and end up blocking this fix.

YesCT’s picture

I'm going to make that test only patch now.

YesCT’s picture

Status: Needs review » Needs work

The last submitted patch, 18: merging_data_types-2693081-15-testsonly.patch, failed testing.

The last submitted patch, 18: merging_data_types-2693081-15-testsonly.patch, failed testing.

YesCT’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
3.88 KB

Those fails look appropriate to me. (combined with the review, discussion and recent changes to the test: rtbc)

Re-uploading the whole patch from #15 so that when the automatic retest runs, it will run on a passing patch so that the status doesn't change to needs work

YesCT’s picture

Issue summary: View changes

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 21: merging_data_types-2693081-15.patch, failed testing.

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

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Leksat’s picture

Status: Needs work » Reviewed & tested by the community

It seems like the last test fail was caused by some CI issue. I retested the last patch and tests are okay.

I also tested this patch manually and I can confirm it works great! For example, it solves page_manager blocks translation issue.

Reverting status to RTBC.

andrewbelcher’s picture

Priority: Normal » Major
Issue tags: -DevDaysMilan +Contributed project blocker

This issue causes problems for contributed modules that run schema checks on of their config. Marking as major ("Block contributed projects with no workaround."). It also causes fatal errors via the UI if the config checker service is enabled (i.e. dev workflows).

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.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed 1fbdcc7 to 8.4.x and 9298caf to 8.3.x. Thanks!

  • alexpott committed 1fbdcc7 on 8.4.x
    Issue #2693081 by yanniboi, YesCT: Merging data types leads to...

  • alexpott committed 9298caf on 8.3.x
    Issue #2693081 by yanniboi, YesCT: Merging data types leads to...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Wim Leers’s picture

Issue tags: +Configuration schema