summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2018-07-13 13:11:18 (GMT)
committerNathaniel Catchpole2018-07-13 13:11:18 (GMT)
commitb55ed6bd46f0dd189c25cbd842ac9495baf41d67 (patch)
tree5f2c2510d83ecb0883a40eca05909e5abe75b942
parent099f4146a5d04b12196ff2962a27fbb045cf2af4 (diff)
Issue #2666392 by alexpott, webflo, xaqrox, Boobaa, dawehner, Berdir: Unable to revert third party settings via config import
-rw-r--r--core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php13
-rw-r--r--core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php16
-rw-r--r--core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php51
-rw-r--r--core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php13
-rw-r--r--core/modules/config/tests/config_test/config/schema/config_test.schema.yml8
-rw-r--r--core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php17
-rw-r--r--core/modules/system/tests/src/Functional/Entity/ConfigEntityImportTest.php31
-rw-r--r--core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php27
-rw-r--r--core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php49
9 files changed, 143 insertions, 82 deletions
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
index 90bb702..1efa344 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php
@@ -4,7 +4,6 @@ namespace Drupal\Core\Config\Entity;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Cache\Cache;
-use Drupal\Core\Config\Schema\SchemaIncompleteException;
use Drupal\Core\Entity\Entity;
use Drupal\Core\Config\ConfigDuplicateUUIDException;
use Drupal\Core\Entity\EntityStorageInterface;
@@ -267,18 +266,8 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
/** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type */
$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']));
- }
-
$id_key = $entity_type->getKey('id');
- foreach ($properties_to_export as $property_name => $export_name) {
+ foreach ($entity_type->getPropertiesToExport($this->id()) as $property_name => $export_name) {
// Special handling for IDs so that computed compound IDs work.
// @see \Drupal\Core\Entity\EntityDisplayBase::id()
if ($property_name == $id_key) {
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 3b90899..e3d38d1 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -450,9 +450,19 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora
$data = $this->mapFromStorageRecords([$values]);
$updated_entity = current($data);
- foreach (array_keys($values) as $property) {
- $value = $updated_entity->get($property);
- $entity->set($property, $value);
+ /** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $entity_type */
+ $entity_type = $this->getEntityType();
+ $id_key = $entity_type->getKey('id');
+ foreach ($entity_type->getPropertiesToExport($updated_entity->get($id_key)) as $property) {
+ if ($property === $this->uuidKey) {
+ // During an update the UUID field should not be copied. Under regular
+ // circumstances the values will be equal. If configuration is written
+ // twice during configuration install the updated entity will not have a
+ // UUID.
+ // @see \Drupal\Core\Config\ConfigInstaller::createConfiguration()
+ continue;
+ }
+ $entity->set($property, $updated_entity->get($property));
}
return $entity;
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
index 11c9ff1..d462adb 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
@@ -3,6 +3,7 @@
namespace Drupal\Core\Config\Entity;
use Drupal\Core\Config\Entity\Exception\ConfigEntityStorageClassException;
+use Drupal\Core\Config\Schema\SchemaIncompleteException;
use Drupal\Core\Entity\EntityType;
use Drupal\Core\Config\ConfigPrefixLengthException;
@@ -142,30 +143,40 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface {
/**
* {@inheritdoc}
*/
- public function getPropertiesToExport() {
+ public function getPropertiesToExport($id = NULL) {
+ if (!empty($this->mergedConfigExport)) {
+ return $this->mergedConfigExport;
+ }
if (!empty($this->config_export)) {
- if (empty($this->mergedConfigExport)) {
- // Always add default properties to be exported.
- $this->mergedConfigExport = [
- 'uuid' => 'uuid',
- 'langcode' => 'langcode',
- 'status' => 'status',
- 'dependencies' => 'dependencies',
- 'third_party_settings' => 'third_party_settings',
- '_core' => '_core',
- ];
- foreach ($this->config_export as $property => $name) {
- if (is_numeric($property)) {
- $this->mergedConfigExport[$name] = $name;
- }
- else {
- $this->mergedConfigExport[$property] = $name;
- }
+ // Always add default properties to be exported.
+ $this->mergedConfigExport = [
+ 'uuid' => 'uuid',
+ 'langcode' => 'langcode',
+ 'status' => 'status',
+ 'dependencies' => 'dependencies',
+ 'third_party_settings' => 'third_party_settings',
+ '_core' => '_core',
+ ];
+ foreach ($this->config_export as $property => $name) {
+ if (is_numeric($property)) {
+ $this->mergedConfigExport[$name] = $name;
+ }
+ else {
+ $this->mergedConfigExport[$property] = $name;
}
}
- return $this->mergedConfigExport;
}
- return NULL;
+ else {
+ // @todo https://www.drupal.org/project/drupal/issues/2949021 Deprecate
+ // fallback to schema.
+ $config_name = $this->getConfigPrefix() . '.' . $id;
+ $definition = \Drupal::service('config.typed')->getDefinition($config_name);
+ if (!isset($definition['mapping'])) {
+ throw new SchemaIncompleteException("Incomplete or missing schema for $config_name");
+ }
+ $this->mergedConfigExport = array_combine(array_keys($definition['mapping']), array_keys($definition['mapping']));
+ }
+ return $this->mergedConfigExport;
}
/**
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php
index 589a63d..76d6557 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php
@@ -65,11 +65,22 @@ interface ConfigEntityTypeInterface extends EntityTypeInterface {
/**
* Gets the config entity properties to export if declared on the annotation.
*
+ * Falls back to determining the properties using configuration schema, if the
+ * config entity properties are not declared.
+ *
+ * param string $id
+ * The ID of the configuration entity. Used when checking schema instead of
+ * the annotation.
+ *
* @return array|null
* The properties to export or NULL if they can not be determine from the
* config entity type annotation.
+ *
+ * @throws \Drupal\Core\Config\Schema\SchemaIncompleteException
+ * Thrown when the configuration entity type does not have the annotation or
+ * a configuration schema.
*/
- public function getPropertiesToExport();
+ public function getPropertiesToExport($id = NULL);
/**
* Gets the keys that are available for fast lookup.
diff --git a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
index c25a577..a6f3550 100644
--- a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
+++ b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
@@ -158,6 +158,14 @@ config_test.foo:
config_test.bar:
type: config_test.foo
+system.action.*.third_party.config_test:
+ type: mapping
+ label: 'Third party setting for action entity'
+ mapping:
+ integer:
+ type: integer
+ label: 'Integer'
+
config_test.validation:
type: config_object
label: 'Configuration type'
diff --git a/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php b/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php
index 36f9398..10c0a7d 100644
--- a/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php
+++ b/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php
@@ -72,13 +72,6 @@ class FieldConfigEntityUnitTest extends UnitTestCase {
protected $fieldStorage;
/**
- * The typed configuration manager used for testing.
- *
- * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
- */
- protected $typedConfigManager;
-
- /**
* The mock field type plugin manager;
*
* @var \Drupal\Core\Field\FieldTypePluginManagerInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -98,8 +91,6 @@ class FieldConfigEntityUnitTest extends UnitTestCase {
$this->uuid = $this->getMock('\Drupal\Component\Uuid\UuidInterface');
- $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
-
$this->fieldTypePluginManager = $this->getMock('Drupal\Core\Field\FieldTypePluginManagerInterface');
$container = new ContainerBuilder();
@@ -107,7 +98,6 @@ class FieldConfigEntityUnitTest extends UnitTestCase {
$container->set('entity_field.manager', $this->entityFieldManager);
$container->set('entity_type.manager', $this->entityTypeManager);
$container->set('uuid', $this->uuid);
- $container->set('config.typed', $this->typedConfigManager);
$container->set('plugin.manager.field.field_type', $this->fieldTypePluginManager);
// Inject the container into entity.manager so it can defer to
// entity_type.manager, etc.
@@ -299,9 +289,10 @@ class FieldConfigEntityUnitTest extends UnitTestCase {
->method('getKey')
->with('id')
->will($this->returnValue('id'));
- $this->typedConfigManager->expects($this->once())
- ->method('getDefinition')
- ->will($this->returnValue(['mapping' => array_fill_keys(array_keys($expected), '')]));
+ $this->entityType->expects($this->once())
+ ->method('getPropertiesToExport')
+ ->with('test_entity_type.test_bundle.field_test')
+ ->will($this->returnValue(array_combine(array_keys($expected), array_keys($expected))));
$export = $field->toArray();
$this->assertEquals($expected, $export);
diff --git a/core/modules/system/tests/src/Functional/Entity/ConfigEntityImportTest.php b/core/modules/system/tests/src/Functional/Entity/ConfigEntityImportTest.php
index b699603..88d9bb5 100644
--- a/core/modules/system/tests/src/Functional/Entity/ConfigEntityImportTest.php
+++ b/core/modules/system/tests/src/Functional/Entity/ConfigEntityImportTest.php
@@ -21,7 +21,7 @@ class ConfigEntityImportTest extends BrowserTestBase {
*
* @var array
*/
- public static $modules = ['action', 'block', 'filter', 'image', 'search', 'search_extra_type'];
+ public static $modules = ['action', 'block', 'filter', 'image', 'search', 'search_extra_type', 'config_test'];
/**
* {@inheritdoc}
@@ -41,6 +41,7 @@ class ConfigEntityImportTest extends BrowserTestBase {
$this->doFilterFormatUpdate();
$this->doImageStyleUpdate();
$this->doSearchPageUpdate();
+ $this->doThirdPartySettingsUpdate();
}
/**
@@ -173,6 +174,34 @@ class ConfigEntityImportTest extends BrowserTestBase {
}
/**
+ * Tests updating of third party settings.
+ */
+ protected function doThirdPartySettingsUpdate() {
+ // Create a test action with a known label.
+ $name = 'system.action.third_party_settings_test';
+
+ /** @var \Drupal\config_test\Entity\ConfigTest $entity */
+ $entity = Action::create([
+ 'id' => 'third_party_settings_test',
+ 'plugin' => 'action_message_action',
+ ]);
+ $entity->save();
+
+ $this->assertIdentical([], $entity->getThirdPartyProviders());
+ // Get a copy of the configuration before the third party setting is added.
+ $no_third_part_setting_config = $this->container->get('config.storage')->read($name);
+
+ // Add a third party setting.
+ $entity->setThirdPartySetting('config_test', 'integer', 1);
+ $entity->save();
+ $this->assertIdentical(1, $entity->getThirdPartySetting('config_test', 'integer'));
+ $has_third_part_setting_config = $this->container->get('config.storage')->read($name);
+
+ // Ensure configuration imports can completely remove third party settings.
+ $this->assertConfigUpdateImport($name, $has_third_part_setting_config, $no_third_part_setting_config);
+ }
+
+ /**
* Tests that a single set of plugin config stays in sync.
*
* @param \Drupal\Core\Entity\EntityWithPluginCollectionInterface $entity
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
index 81d424b..e2828cb 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
@@ -8,7 +8,6 @@
namespace Drupal\Tests\Core\Config\Entity;
use Drupal\Component\Plugin\PluginManagerInterface;
-use Drupal\Core\Config\Schema\SchemaIncompleteException;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\Language;
@@ -553,32 +552,6 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
}
/**
- * @covers ::toArray
- */
- public function testToArraySchemaFallback() {
- $this->typedConfigManager->expects($this->once())
- ->method('getDefinition')
- ->will($this->returnValue(['mapping' => ['id' => '', 'dependencies' => '']]));
- $this->entityType->expects($this->any())
- ->method('getPropertiesToExport')
- ->willReturn([]);
- $properties = $this->entity->toArray();
- $this->assertInternalType('array', $properties);
- $this->assertEquals(['id' => $this->entity->id(), 'dependencies' => []], $properties);
- }
-
- /**
- * @covers ::toArray
- */
- public function testToArrayFallback() {
- $this->entityType->expects($this->any())
- ->method('getPropertiesToExport')
- ->willReturn([]);
- $this->setExpectedException(SchemaIncompleteException::class);
- $this->entity->toArray();
- }
-
- /**
* @covers ::getThirdPartySetting
* @covers ::setThirdPartySetting
* @covers ::getThirdPartySettings
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php
index c5d4c1c..5c1e845 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php
@@ -2,6 +2,9 @@
namespace Drupal\Tests\Core\Config\Entity;
+use Drupal\Core\Config\Schema\SchemaIncompleteException;
+use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Config\Entity\ConfigEntityType;
use Drupal\Core\Config\Entity\Exception\ConfigEntityStorageClassException;
@@ -13,6 +16,23 @@ use Drupal\Core\Config\Entity\Exception\ConfigEntityStorageClassException;
class ConfigEntityTypeTest extends UnitTestCase {
/**
+ * The mocked typed config manager.
+ *
+ * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $typedConfigManager;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ $this->typedConfigManager = $this->getMock(TypedConfigManagerInterface::class);
+ $container = new ContainerBuilder();
+ $container->set('config.typed', $this->typedConfigManager);
+ \Drupal::setContainer($container);
+ }
+
+ /**
* Sets up a ConfigEntityType object for a given set of values.
*
* @param array $definition
@@ -138,11 +158,6 @@ class ConfigEntityTypeTest extends UnitTestCase {
public function providerGetPropertiesToExport() {
$data = [];
$data[] = [
- [],
- NULL,
- ];
-
- $data[] = [
[
'config_export' => [
'id',
@@ -177,4 +192,28 @@ class ConfigEntityTypeTest extends UnitTestCase {
return $data;
}
+ /**
+ * @covers ::getPropertiesToExport
+ */
+ public function testGetPropertiesToExportSchemaFallback() {
+ $this->typedConfigManager->expects($this->once())
+ ->method('getDefinition')
+ ->will($this->returnValue(['mapping' => ['id' => '', 'dependencies' => '']]));
+ $config_entity_type = new ConfigEntityType([
+ 'id' => 'example_config_entity_type',
+ ]);
+ $this->assertEquals(['id' => 'id', 'dependencies' => 'dependencies'], $config_entity_type->getPropertiesToExport('test'));
+ }
+
+ /**
+ * @covers ::getPropertiesToExport
+ */
+ public function testGetPropertiesToExportException() {
+ $config_entity_type = new ConfigEntityType([
+ 'id' => 'example_config_entity_type',
+ ]);
+ $this->setExpectedException(SchemaIncompleteException::class);
+ $config_entity_type->getPropertiesToExport();
+ }
+
}