Problem/Motivation

Its not possible to remove the last third party setting on config import.

Proposed resolution

ConfigEntityStorage::updateFromStorageRecord() creates a new entity and copies the values over to the existing entity. This then does not account for properties that are not in the export. The solution is to iterate over all the properties that could be exported. This means we need to refactor the code in ConfigEntityBase::toArray() so we can get the property list in the ConfigEntityStorage class.

Remaining tasks

User interface changes

None

API changes

Move schema fallback from ConfigEntityBase::toArray() to ConfigEntityType::getPropertiesToExport(). Add optional $id argument to ConfigEntityType::getPropertiesToExport() that is used when using the schema fallback. The $id argument is provided when using ConfigEntityBase::toArray() so there is no loss in functionality.

Data model changes

None

CommentFileSizeAuthor
#50 2666392-50.patch16.37 KBalexpott
#50 45-50-interdiff.txt847 bytesalexpott
#45 2666392-45.patch16.37 KBalexpott
#45 43-45-interdiff.txt1.25 KBalexpott
#43 2666392-43.patch16.13 KBalexpott
#39 2666392-39.patch16.17 KBalexpott
#39 38-39-interdiff.txt724 bytesalexpott
#38 2666392-38.patch16.1 KBalexpott
#38 37-38-interdiff.txt6.18 KBalexpott
#37 2666392-37.patch10.38 KBxaqrox
#37 33-37-interdiff.txt5.96 KBxaqrox
#33 2666392-33.patch10.16 KBalexpott
#33 32-33-interdiff.txt8.78 KBalexpott
#32 2666392-32.patch7.47 KBalexpott
#32 29-32-interdiff.txt884 bytesalexpott
#29 2666392-29.patch7.46 KBalexpott
#29 17-29-interdiff.txt4.62 KBalexpott
#17 2666392-17.patch7.16 KBalexpott
#17 13-17-interdiff.txt1.23 KBalexpott
#13 2666392-13.patch6.52 KBalexpott
#13 11-13-interdiff.txt1.87 KBalexpott
#11 2666392-11.patch6.05 KBalexpott
#11 2-11-interdiff.txt3.33 KBalexpott
#9 2666392-9.patch37.31 KBBoobaa
#6 2666392-6.patch37.28 KBwebflo
#3 2666392-2.patch3.24 KBwebflo
#2 2666392-1.patch2.72 KBwebflo
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

webflo created an issue. See original summary.

webflo’s picture

The path should fail because its a test only patch.

webflo’s picture

The config export should contain the the empty third_party_settings property. ConfigEntityStorage::updateFromStorageRecord is related for the import, the foreach in line 458 iterates over the properties of the imported data only and not all properties of the config entity.

The unset was introduced in #2361775: Third party settings dependencies cause config entity deletion.

The last submitted patch, 2: 2666392-1.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 3: 2666392-2.patch, failed testing.

webflo’s picture

Status: Needs work » Needs review
FileSize
37.28 KB

Status: Needs review » Needs work

The last submitted patch, 6: 2666392-6.patch, failed testing.

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

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

Boobaa’s picture

Status: Needs work » Needs review
FileSize
37.31 KB

Rerolled the patch from #6 which solves the problem for me (and applies cleanly both to latest 8.1.x and 8.2.x).

Status: Needs review » Needs work

The last submitted patch, 9: 2666392-9.patch, failed testing.

alexpott’s picture

Priority: Normal » Major
Status: Needs work » Needs review
FileSize
3.33 KB
6.05 KB

I think this is exposing a bug in ConfigEntityStorage::updateFromStorageRecord() it is not copying over the values from the new entity to the existing entity properly.

This solution is completely different from the the solution in #3 because it is a generic solution. Interdiff is to #2 - the test only patch.

alexpott’s picture

Issue summary: View changes
alexpott’s picture

For me this is at least a major bug because config imports produce an unexpected result - i.e. you can't remove the data. Also realised the new method on ConfigEntityBase needs to go on the interface. The reason it is underscored is because ConfigEntityBase will be one of the most extend classes we have and there is no point breaking existing code.

webflo’s picture

Issue tags: +DevDaysMilan

The last submitted patch, 11: 2666392-11.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 13: 2666392-13.patch, failed testing.

alexpott’s picture

Status: Needs work » Needs review
FileSize
1.23 KB
7.16 KB

Every time I change this interface I see this fail in ViewUI :)

Also we don't need to be mucking with uuid fields in updating an entity.

Berdir’s picture

  1. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
    @@ -267,15 +267,7 @@ public function toArray() {
         $entity_type = $this->getEntityType();
     
    -    $properties_to_export = $entity_type->getPropertiesToExport();
    -    if (empty($properties_to_export)) {
    -      $config_name = $entity_type->getConfigPrefix() . '.' . $this->id();
    -      $definition = $this->getTypedConfig()->getDefinition($config_name);
    -      if (!isset($definition['mapping'])) {
    -        throw new SchemaIncompleteException("Incomplete or missing schema for $config_name");
    -      }
    -      $properties_to_export = array_combine(array_keys($definition['mapping']), array_keys($definition['mapping']));
    -    }
    +    $properties_to_export = $this->_getPropertiesToExport();
    

    There are some config entities that override toArray() and do special things.

    If they add/remove properties completely, could that cause a problem in that the new method would not work as expected? Haven't really thought it through or identified a specific problem, just want to make sure that we don't introduce bugs for them.

    Some of the overrides might also no longer be necessary, some example implementations:

    EntityDisplayBase, just removes sub-keys
    Flag (unecessary I think)
    Currency/CurrencyLocale (not sure, many things could be removed probably but Xano likes to do special things ;))
    search_api Server
    FilterFormat (the roles thing is both unproblematic here I think and weird in general)

  2. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
    @@ -267,15 +267,7 @@ public function toArray() {
         foreach ($properties_to_export as $property_name => $export_name) {
    @@ -299,6 +291,25 @@ public function toArray() {
    
    @@ -299,6 +291,25 @@ public function toArray() {
       }
     
       /**
    +   * {@inheritdoc}
    +   */
    
    +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
    @@ -217,4 +217,21 @@ public function trustData();
    +   *
    +   * @todo Remove underscore in Drupal 9.
    +   */
    +  public function _getPropertiesToExport();
    

    I think we did add new methods without underscore in minor versions before but probably none that are extended so often.

Xano’s picture

+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
@@ -217,4 +217,21 @@ public function trustData();
+  public function _getPropertiesToExport();

Can we add this to a new, optional interface?

alexpott’s picture

@Xano do you have config entities not extending from ConfigEntityBase?

alexpott’s picture

Xano’s picture

@alexpott: I haven't, but it may break tests using Prophecy (unmocked method calls raise errors). It's technically a BC break, though, and I'm wondering if there is a feasible way to avoid that, and make it pretty again in D9.

alexpott’s picture

We explicitly stated that EntityInterface are subject to change and that you should inherit from the base classes and that we would change these interfaces by making additions in minors.

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.

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.

dawehner’s picture

If they add/remove properties completely, could that cause a problem in that the new method would not work as expected? Haven't really thought it through or identified a specific problem, just want to make sure that we don't introduce bugs for them.

That's a totally valid question to think about.
I think this should not be an issue. When the configuration is removed, it won't be part of the schema, as it will never be exported to YML files in the first place, so the expected data doesn't change.

Can we add this to a new, optional interface?
@Xano do you have config entities not extending from ConfigEntityBase?

I doubt this kind of change will land in a patch release anyway. When its not a patch release we have clearly stated that adding methods is possible.

  1. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php
    @@ -217,4 +217,21 @@ public function trustData();
    +   *
    +   * @todo Remove underscore in Drupal 9.
    +   */
    +  public function _getPropertiesToExport();
    

    Personally as long we do that in a minor release, not using the underscore would be find.

  2. +++ b/core/modules/system/src/Tests/Entity/ConfigEntityImportTest.php
    @@ -172,6 +173,33 @@ protected function doSearchPageUpdate() {
    +    $custom_data = $this->container->get('config.storage')->read($name);
    ...
    +    $original_data = $this->container->get('config.storage')->read($name);
    

    Can we use '.sync' to make this test code more clear?

dawehner’s picture

albertski’s picture

I ran into a problem where we removed field groups from our node display but during configuration import on dev and production, it would not import. I wouldn't get any errors or anything.

Patch #17 fixed the issue for me. (Thanks @Berdir for pointing me here from my Drupal Answers question).

Not sure if I should mark this as RTBC or Needs Work. (I'm just not a big fan of having the underscore in _getPropertiesToExport()).

alexpott’s picture

Re #26 - thanks for the review. I've fixed point 1. Re point 2. I'm not sure what you are getting at \Drupal\Tests\system\Functional\Entity\ConfigEntityImportTest::assertConfigUpdateImport() works by writing to the sync directory. I've improved the variable names - hopefully that helps.

alexpott’s picture

Issue summary: View changes
dawehner’s picture

This looks great for me!

+++ b/core/modules/system/tests/src/Functional/Entity/ConfigEntityImportTest.php
@@ -187,16 +187,17 @@ protected function doThirdPartySettingsUpdate() {
+    // Ensure that a configuration import can remove a third party settings.

I guess this should be singular here? A third party setting.

alexpott’s picture

Fixed #31 = thanks @dawehner

alexpott’s picture

hmmm... I've looked at this patch some more and I'm uncomfortable with adding getPropertiesToExport() to the ConfigEntityInterface when we have exactly the same method on the ConfigEntityTypeInterface. I think what we should do is move the config schema checking fallback to the ConfigEntityType implementation and deprecate it - basically make the config_export mandatory in Drupal 9. This is good for performance and doing things one way.

Status: Needs review » Needs work

The last submitted patch, 33: 2666392-33.patch, failed testing.

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.

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

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

xaqrox’s picture

Rerolled patch against 8.4.5, cuz I need it.

alexpott’s picture

Status: Needs work » Needs review
FileSize
6.18 KB
16.1 KB

Thanks for reminding me of this issue! Here's a patch with fixed tests.

alexpott’s picture

Let's move the deprecation to another issue so this can be just about fixing the bug. See #2949021: Deprecate schema fallback in ConfigEntityType::getPropertiesToExport

alexpott’s picture

Issue tags: -Needs change record

Created a change record - https://www.drupal.org/node/2949023

alexpott’s picture

Issue summary: View changes
mdrescher’s picture

Hi,

What's the status on this one? I am Running Drupal 8.5 in production, and got stung by this with the DisplaySuite module!

Can I use the patch in #37, #38 or #39 in 8.5?

Cheers,
Michel

alexpott’s picture

Rerolled.

@mdrescher the latest patch is probably the one to use. Out of the three you've asked about #39.

webflo’s picture

+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -450,9 +450,16 @@ public function updateFromStorageRecord(ConfigEntityInterface $entity, array $va
 
...
+      if ($property === $uuid_key) {
+        // The UUID field should not be copied.
+        continue;
+      }

I could not find this hunk it the old core? Could you explain thy the special case for uuid is required? Thanks!

alexpott’s picture

+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -450,9 +450,16 @@ public function updateFromStorageRecord(ConfigEntityInterface $entity, array $va
-    foreach (array_keys($values) as $property) {
...
+    foreach ($entity_type->getPropertiesToExport($updated_entity->get($id_key)) as $property) {

It's because we're using the annotation (or schema) to get the list of properties to update. So both UUID and third_party are in there even if they are not in the incoming values. Without this change Drupal\KernelTests\Core\Config\ConfigImporterTest will fail.

That said the uuid key is hardcoded in config storage so let's use that. Config Entities need to have a key of uuid - there's just no way to use a different value and the configuration system work. So there's one little bit of tidy up we can do.

I've also improved the comment to explain how this occurs.

webflo’s picture

Status: Needs review » Reviewed & tested by the community

The new comment looks good. I reviewed the patch with @alexpott in person at Drupal Dev Days. I think this is ready to go.

The last submitted patch, 37: 2666392-37.patch, failed testing. View results

mdrescher’s picture

@alexpott, comment #43

In the end I didn't use the patch, but got rid of the settings through manual intervention on PROD and committing to master, which isn't ideal, but it worked.

Thanks for working on this!

catch’s picture

Two minor issues, otherwise I think this is OK. It's hard to follow with the annotation and configuration schema fallback but agreed deprecating it in a follow-up is the best option here.

  1. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
    @@ -142,30 +143,40 @@ protected function checkStorageClass($class) {
    +      $definition = \Drupal::service('config.typed')->getDefinition($config_name);
    
    +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php
    @@ -65,11 +65,22 @@ public function getConfigPrefix();
    +   *   Thrown when the configuration entity type does not have the annotation or
    

    Is this not injected because we want to remove the code path? If so is it worth a comment to say that explicitly

  2. +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php
    @@ -65,11 +65,22 @@ public function getConfigPrefix();
        *
    +   * If the config entity properties are not declared it will fallback to
    +   * determining the properties using configuration schema.
    +   *
    

    We should reverse the sentence, the 'it' is a bit confusing in there.

    "Falls back to determining the properties using configuration schema, if the config entity properties are not declared".

alexpott’s picture

Re #49.1 Not really - it's because service injection into an entity type class it not possible. See \Drupal\Core\Entity\EntityType::getBundleConfigDependency() and \Drupal\Core\Entity\EntityType::getBundleLabel().

Fixed .2

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed b55ed6b and pushed to 8.6.x. Thanks!

  • catch committed b55ed6b on 8.6.x
    Issue #2666392 by alexpott, webflo, xaqrox, Boobaa, dawehner, Berdir:...
Wim Leers’s picture

Status: Fixed » Active

Didn't this introduce a subtle BC break?

Per the CR (https://www.drupal.org/node/2949023):

In Drupal 8.6 all of the functionality is present in ConfigEntityType::getPropertiesToExport() which now optionally is passed the configuration entity ID. Without the ID we cannot fallback to schema.

But "properties to export" only is referring to top-level schema keys, and those are always the same, aren't they? There are situations where you don't have a configuration entity ID to pass in, yet still need the schema fallback — for example when determining which top-level keys ("fields") will be exposed via REST API or JSON API or GraphQL for a configuration entity type.

(We encountered this in #2977669: Spec Compliance: some entity types have an "id", "type" or "uuid" field, this violates the spec. First reported at #2483407-33: Allow configuration schema fallback in ConfigEntityType::getPropertiesToExport() to work without an ID.)

alexpott’s picture

Status: Active » Fixed

@Wim Leers nope this didn't introduce any BC - it was the same before this patch was committed. If we didn't have an ID then schema fallback didn't weork. Please don't re-open this issue. Let's continue to discuss the problem in #2483407: Allow configuration schema fallback in ConfigEntityType::getPropertiesToExport() to work without an ID.

Wim Leers’s picture

Okay, so this didn't turn #2483407: Allow configuration schema fallback in ConfigEntityType::getPropertiesToExport() to work without an ID into a duplicate of this after all. Thanks for clarifying!

Sorry for reopening — looking back, I don't know how I concluded this was a subtle BC break… 🤔

P.S.: this issue's CR was not yet published — did that.

Wim Leers’s picture

  • catch committed 16efa3b on 8.7.x
    Issue #2986901 by gabesullice, alexpott: Followup for #2666392:...

  • catch committed f28f562 on 8.6.x
    Issue #2986901 by gabesullice, alexpott: Followup for #2666392:...

Status: Fixed » Closed (fixed)

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

pfrenssen’s picture

Issue summary: View changes