From e0aae8c26ae3367b96d2e49a8beb05a441a9f8fc Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole Date: Tue, 5 May 2015 11:47:16 +0100 Subject: [PATCH] Issue #2432791 by alexpott, vijaycs85, tim.plunkett, joshtaylor, Fabianx, Berdir, yched, bojanz: Skip Config::save schema validation of config data for trusted data. --- core/includes/file.inc | 5 +- core/includes/install.inc | 6 +- core/includes/module.inc | 6 +- core/lib/Drupal/Core/Config/Config.php | 26 ++++---- .../Drupal/Core/Config/ConfigInstaller.php | 4 +- .../Core/Config/Entity/ConfigEntityBase.php | 60 +++++++++++++++---- .../Config/Entity/ConfigEntityInterface.php | 23 +++++++ .../Config/Entity/ConfigEntityStorage.php | 14 ++++- .../Core/Config/Entity/ConfigEntityType.php | 44 ++++++++++++++ .../Entity/ConfigEntityTypeInterface.php | 9 +++ .../Drupal/Core/Config/ImmutableConfig.php | 2 +- .../Drupal/Core/Config/StorableConfigBase.php | 9 ++- .../Core/Datetime/Entity/DateFormat.php | 8 ++- .../Core/Entity/Entity/EntityFormDisplay.php | 8 +++ .../Core/Entity/Entity/EntityFormMode.php | 6 ++ .../Core/Entity/Entity/EntityViewDisplay.php | 8 +++ .../Core/Entity/Entity/EntityViewMode.php | 6 ++ .../Drupal/Core/Extension/ModuleInstaller.php | 9 ++- .../Drupal/Core/Extension/ThemeHandler.php | 9 ++- .../Core/Field/Entity/BaseFieldOverride.php | 14 +++++ .../Core/Installer/Form/SiteConfigureForm.php | 14 ++--- .../Core/Menu/StaticMenuLinkOverrides.php | 21 +++++-- core/modules/block/src/Entity/Block.php | 10 ++++ .../src/Entity/BlockContentType.php | 6 ++ .../book/config/install/node.type.book.yml | 2 + .../comment/src/Entity/CommentType.php | 6 ++ .../config/src/Tests/ConfigCRUDTest.php | 8 +++ .../config/src/Tests/ConfigEntityUnitTest.php | 23 +++++++ .../config/src/Tests/ConfigInstallTest.php | 10 +--- .../config/src/Tests/ConfigSchemaTest.php | 1 + .../config_schema_test.schema_in_install.yml | 1 - .../schema/config_schema_test.schema.yml | 8 --- .../config/install/config_test.types.yml | 2 +- .../optional/config_test.dynamic.override.yml | 2 +- .../config_test.dynamic.override_unmet.yml | 2 +- .../contact/src/Entity/ContactForm.php | 7 +++ core/modules/editor/src/Entity/Editor.php | 6 ++ core/modules/field/src/Entity/FieldConfig.php | 14 +++++ .../field/src/Entity/FieldStorageConfig.php | 13 ++++ .../src/Unit/FieldConfigEntityUnitTest.php | 2 +- .../Unit/FieldStorageConfigEntityUnitTest.php | 9 +-- .../field_ui/src/Tests/EntityDisplayTest.php | 4 +- .../file/config/optional/views.view.files.yml | 2 +- .../filter/src/Entity/FilterFormat.php | 7 +++ .../forum/config/install/node.type.forum.yml | 2 + .../install/taxonomy.vocabulary.forums.yml | 2 + core/modules/image/src/Entity/ImageStyle.php | 5 ++ .../src/Config/LanguageConfigOverride.php | 15 +++-- .../system.action.node_promote_action.yml | 3 + .../system.action.node_publish_action.yml | 3 + core/modules/node/src/Entity/NodeType.php | 9 +++ .../Plugin/Field/FieldType/ListFloatItem.php | 7 +++ .../Field/FieldType/ListIntegerItem.php | 7 +++ .../Plugin/Field/FieldType/ListItemBase.php | 15 ++++- .../Plugin/Field/FieldType/ListStringItem.php | 7 +++ ...field.storage.node.field_options_float.yml | 2 +- core/modules/rdf/src/Entity/RdfMapping.php | 7 +++ core/modules/search/src/Entity/SearchPage.php | 8 +++ core/modules/shortcut/shortcut.install | 4 +- core/modules/shortcut/shortcut.module | 2 +- .../shortcut/src/Entity/ShortcutSet.php | 4 ++ core/modules/system/src/Entity/Action.php | 7 +++ core/modules/system/src/Entity/Menu.php | 6 ++ core/modules/system/system.install | 2 +- .../config/install/core.date_format.fancy.yml | 2 + .../taxonomy/src/Entity/Vocabulary.php | 7 +++ core/modules/tour/src/Entity/Tour.php | 7 +++ .../optional/views.view.user_admin_people.yml | 2 +- core/modules/user/src/Entity/Role.php | 7 +++ core/modules/user/user.module | 8 +-- core/modules/views/src/Entity/View.php | 11 ++++ .../views/display/DisplayPluginBase.php | 2 +- core/modules/views_ui/src/ViewUI.php | 14 +++++ core/profiles/minimal/minimal.install | 4 +- core/profiles/standard/standard.install | 8 +-- core/profiles/standard/standard.profile | 2 +- .../optional/config_test.dynamic.override.yml | 2 +- .../config_test.dynamic.override_unmet.yml | 2 +- .../Entity/ConfigEntityBaseUnitTest.php | 48 ++++++++++++++- .../Config/Entity/ConfigEntityStorageTest.php | 14 ++++- .../Config/Entity/ConfigEntityTypeTest.php | 56 +++++++++++++++++ .../Core/Menu/StaticMenuLinkOverridesTest.php | 10 +++- 82 files changed, 664 insertions(+), 115 deletions(-) delete mode 100644 core/modules/config/tests/config_schema_test/config/install/config_schema_test.schema_in_install.yml diff --git a/core/includes/file.inc b/core/includes/file.inc index 858c4a6de5af..60cec1c347e5 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -1215,8 +1215,9 @@ function file_directory_temp() { // everything to use slash which is supported on all platforms. $temporary_directory = str_replace('\\', '/', $temporary_directory); } - // Save the path of the discovered directory. - $config->set('path.temporary', $temporary_directory)->save(); + // Save the path of the discovered directory. Do not check config schema on + // save. + $config->set('path.temporary', (string) $temporary_directory)->save(TRUE); } return $temporary_directory; diff --git a/core/includes/install.inc b/core/includes/install.inc index 7e0e32e65cad..d56c44f3fe11 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -619,9 +619,9 @@ function drupal_install_system($install_state) { // Ensure default language is saved. if (isset($install_state['parameters']['langcode'])) { \Drupal::configFactory()->getEditable('system.site') - ->set('langcode', $install_state['parameters']['langcode']) - ->set('default_langcode', $install_state['parameters']['langcode']) - ->save(); + ->set('langcode', (string) $install_state['parameters']['langcode']) + ->set('default_langcode', (string) $install_state['parameters']['langcode']) + ->save(TRUE); } } diff --git a/core/includes/module.inc b/core/includes/module.inc index 0f1b0d8cda27..8f8bf9c046ab 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -179,10 +179,12 @@ function drupal_required_modules() { function module_set_weight($module, $weight) { $extension_config = \Drupal::configFactory()->getEditable('core.extension'); if ($extension_config->get("module.$module") !== NULL) { + // Pre-cast the $weight to an integer so that we can save this without using + // schema. This is a performance improvement for module installation. $extension_config - ->set("module.$module", $weight) + ->set("module.$module", (int) $weight) ->set('module', module_config_sort($extension_config->get('module'))) - ->save(); + ->save(TRUE); // Prepare the new module list, sorted by weight, including filenames. // @see \Drupal\Core\Extension\ModuleHandler::install() diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index 51ade6ce736f..19b42f0af83c 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -203,22 +203,24 @@ class Config extends StorableConfigBase { /** * {@inheritdoc} */ - public function save() { + public function save($has_trusted_data = FALSE) { // Validate the configuration object name before saving. static::validateName($this->name); // If there is a schema for this configuration object, cast all values to // conform to the schema. - if ($this->typedConfigManager->hasConfigSchema($this->name)) { - // Ensure that the schema wrapper has the latest data. - $this->schemaWrapper = NULL; - foreach ($this->data as $key => $value) { - $this->data[$key] = $this->castValue($key, $value); + if (!$has_trusted_data) { + if ($this->typedConfigManager->hasConfigSchema($this->name)) { + // Ensure that the schema wrapper has the latest data. + $this->schemaWrapper = NULL; + foreach ($this->data as $key => $value) { + $this->data[$key] = $this->castValue($key, $value); + } } - } - else { - foreach ($this->data as $key => $value) { - $this->validateValue($key, $value); + else { + foreach ($this->data as $key => $value) { + $this->validateValue($key, $value); + } } } @@ -229,6 +231,9 @@ class Config extends StorableConfigBase { $this->isNew = FALSE; $this->eventDispatcher->dispatch(ConfigEvents::SAVE, new ConfigCrudEvent($this)); $this->originalData = $this->data; + // Potentially configuration schema could have changed the underlying data's + // types. + $this->resetOverriddenData(); return $this; } @@ -302,4 +307,5 @@ class Config extends StorableConfigBase { } } } + } diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php index c109ea747c67..082fa6320164 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -304,11 +304,11 @@ class ConfigInstaller implements ConfigInstallerInterface { $entity = $entity_storage->createFromStorageRecord($new_config->get()); } if ($entity->isInstallable()) { - $entity->save(); + $entity->trustData()->save(); } } else { - $new_config->save(); + $new_config->save(TRUE); } } } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php index 0ca35a539caa..56603c7f3cae 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -105,6 +105,13 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface */ protected $third_party_settings = array(); + /** + * Trust supplied data and not use configuration schema on save. + * + * @var bool + */ + protected $trustedData = FALSE; + /** * Overrides Entity::__construct(). */ @@ -265,22 +272,31 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface */ public function toArray() { $properties = array(); - $config_name = $this->getEntityType()->getConfigPrefix() . '.' . $this->id(); - $definition = $this->getTypedConfig()->getDefinition($config_name); - if (!isset($definition['mapping'])) { - throw new SchemaIncompleteException(SafeMarkup::format('Incomplete or missing schema for @config_name', array('@config_name' => $config_name))); + /** @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(SafeMarkup::format('Incomplete or missing schema for @config_name', array('@config_name' => $config_name))); + } + $properties_to_export = array_combine(array_keys($definition['mapping']), array_keys($definition['mapping'])); } - $id_key = $this->getEntityType()->getKey('id'); - foreach (array_keys($definition['mapping']) as $name) { + + $id_key = $entity_type->getKey('id'); + foreach ($properties_to_export as $property_name => $export_name) { // Special handling for IDs so that computed compound IDs work. // @see \Drupal\Core\Entity\EntityDisplayBase::id() - if ($name == $id_key) { - $properties[$name] = $this->id(); + if ($property_name == $id_key) { + $properties[$export_name] = $this->id(); } else { - $properties[$name] = $this->get($name); + $properties[$export_name] = $this->get($property_name); } } + if (empty($this->third_party_settings)) { unset($properties['third_party_settings']); } @@ -328,7 +344,7 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface throw new ConfigDuplicateUUIDException(SafeMarkup::format('Attempt to save a configuration entity %id with UUID %uuid when this entity already exists with UUID %original_uuid', array('%id' => $this->id(), '%uuid' => $this->uuid(), '%original_uuid' => $original->uuid()))); } } - if (!$this->isSyncing()) { + if (!$this->isSyncing() && !$this->trustedData) { // Ensure the correct dependencies are present. If the configuration is // being written during a configuration synchronization then there is no // need to recalculate the dependencies. @@ -572,4 +588,28 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface return TRUE; } + /** + * {@inheritdoc} + */ + public function trustData() { + $this->trustedData = TRUE; + return $this; + } + + /** + * {@inheritdoc} + */ + public function hasTrustedData() { + return $this->trustedData; + } + + /** + * {@inheritdoc} + */ + public function save() { + $return = parent::save(); + $this->trustedData = FALSE; + return $return; + } + } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php index 3d688a5f8cf7..76809ed8b4a8 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php @@ -203,4 +203,27 @@ interface ConfigEntityInterface extends EntityInterface, ThirdPartySettingsInter */ public function isInstallable(); + /** + * Sets that the data should be trusted. + * + * If the data is trusted then dependencies will not be calculated on save and + * schema will not be used to cast the values. Generally this is only used + * during module and theme installation. Once the config entity has been saved + * the data will no longer be marked as trusted. This is an optimization for + * creation of configuration during installation. + * + * @return $this + * + * @see \Drupal\Core\Config\ConfigInstaller::createConfiguration() + */ + public function trustData(); + + /** + * Gets whether on not the data is trusted. + * + * @return bool + * TRUE if the configuration data is trusted, FALSE if not. + */ + public function hasTrustedData(); + } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php index 2c3e79891b22..48021733f911 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -256,7 +256,19 @@ class ConfigEntityStorage extends EntityStorageBase implements ConfigEntityStora // Retrieve the desired properties and set them in config. $config->setData($this->mapToStorageRecord($entity)); - $config->save(); + $config->save($entity->hasTrustedData()); + + // Update the entity with the values stored in configuration. It is possible + // that configuration schema has casted some of the values. + if (!$entity->hasTrustedData()) { + $data = $this->mapFromStorageRecords(array($config->get())); + $updated_entity = current($data); + + foreach (array_keys($config->get()) as $property) { + $value = $updated_entity->get($property); + $entity->set($property, $value); + } + } return $is_new ? SAVED_NEW : SAVED_UPDATED; } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php index 0cb9772ecc65..f15eef51e74d 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php @@ -34,6 +34,22 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface { */ protected $static_cache = FALSE; + /** + * The list of configuration entity properties to export from the annotation. + * + * @var array + */ + protected $config_export = []; + + /** + * The result of merging config_export annotation with the defaults. + * + * This is stored on the class so that it does not have to be recalculated. + * + * @var array + */ + protected $mergedConfigExport = []; + /** * {@inheritdoc} * @@ -146,4 +162,32 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface { } } + /** + * {@inheritdoc} + */ + public function getPropertiesToExport() { + 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', + ]; + 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; + } + } diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php index a24c96fa1f5f..0f26ae08002c 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityTypeInterface.php @@ -61,4 +61,13 @@ interface ConfigEntityTypeInterface extends EntityTypeInterface { */ public function getConfigPrefix(); + /** + * Gets the config entity properties to export if declared on the annotation. + * + * @return array|NULL + * The properties to export or NULL if they can not be determine from the + * config entity type annotation. + */ + public function getPropertiesToExport(); + } diff --git a/core/lib/Drupal/Core/Config/ImmutableConfig.php b/core/lib/Drupal/Core/Config/ImmutableConfig.php index e6938fb010bd..8435f7110324 100644 --- a/core/lib/Drupal/Core/Config/ImmutableConfig.php +++ b/core/lib/Drupal/Core/Config/ImmutableConfig.php @@ -44,7 +44,7 @@ class ImmutableConfig extends Config { /** * {@inheritdoc} */ - public function save() { + public function save($has_trusted_data = FALSE) { throw new ImmutableConfigException(SafeMarkup::format('Can not save immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()])); } diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php index 625900c28f9c..d5ea532a8ac8 100644 --- a/core/lib/Drupal/Core/Config/StorableConfigBase.php +++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php @@ -66,11 +66,18 @@ abstract class StorableConfigBase extends ConfigBase { /** * Saves the configuration object. * + * @param bool $has_trusted_data + * Set to TRUE is the configuration data has already been checked to ensure + * it conforms to schema. Generally this is only used during module and + * theme installation. + * * Must invalidate the cache tags associated with the configuration object. * * @return $this + * + * @see \Drupal\Core\Config\ConfigInstaller::createConfiguration() */ - abstract public function save(); + abstract public function save($has_trusted_data = FALSE); /** * Deletes the configuration object. diff --git a/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php b/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php index f8bb4426297f..fa1de8666fcc 100644 --- a/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php +++ b/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php @@ -25,7 +25,13 @@ use Drupal\Core\Datetime\DateFormatInterface; * "label" = "label" * }, * admin_permission = "administer site configuration", - * list_cache_tags = { "rendered" } + * list_cache_tags = { "rendered" }, + * config_export = { + * "id", + * "label", + * "locked", + * "pattern", + * } * ) */ class DateFormat extends ConfigEntityBase implements DateFormatInterface { diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php index ae4b46daed03..d0280a046276 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php @@ -23,6 +23,14 @@ use Drupal\Core\Form\FormStateInterface; * entity_keys = { * "id" = "id", * "status" = "status" + * }, + * config_export = { + * "id", + * "targetEntityType", + * "bundle", + * "mode", + * "content", + * "hidden", * } * ) */ diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php index 7f8371ad2492..1fed80c611d3 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php @@ -33,6 +33,12 @@ use Drupal\Core\Entity\EntityFormModeInterface; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "label", + * "targetEntityType", + * "cache", * } * ) */ diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php index 5b28f764f72b..db56e8b85cfd 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php @@ -24,6 +24,14 @@ use Drupal\Core\Entity\EntityDisplayBase; * entity_keys = { * "id" = "id", * "status" = "status" + * }, + * config_export = { + * "id", + * "targetEntityType", + * "bundle", + * "mode", + * "content", + * "hidden", * } * ) */ diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php index 80a38758a883..08eb6619485a 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php @@ -35,6 +35,12 @@ use Drupal\Core\Entity\EntityViewModeInterface; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "label", + * "targetEntityType", + * "cache", * } * ) */ diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php index caddbad05ad7..6f65a73d4546 100644 --- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php @@ -155,10 +155,12 @@ class ModuleInstaller implements ModuleInstallerInterface { // exceptions if the configuration is not valid. $config_installer->checkConfigurationToInstall('module', $module); + // Save this data without checking schema. This is a performance + // improvement for module installation. $extension_config ->set("module.$module", 0) ->set('module', module_config_sort($extension_config->get('module'))) - ->save(); + ->save(TRUE); // Prepare the new module list, sorted by weight, including filenames. // This list is used for both the ModuleHandler and DrupalKernel. It @@ -385,8 +387,9 @@ class ModuleInstaller implements ModuleInstallerInterface { // Remove the schema. drupal_uninstall_schema($module); - // Remove the module's entry from the config. - \Drupal::configFactory()->getEditable('core.extension')->clear("module.$module")->save(); + // Remove the module's entry from the config. Don't check schema when + // uninstalling a module since we are only clearing a key. + \Drupal::configFactory()->getEditable('core.extension')->clear("module.$module")->save(TRUE); // Update the module handler to remove the module. // The current ModuleHandler instance is obsolete with the kernel rebuild diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index 57a317e7f304..9d790ae081f6 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -260,10 +260,11 @@ class ThemeHandler implements ThemeHandlerInterface { // configuration then stop installing. $this->configInstaller->checkConfigurationToInstall('theme', $key); - // The value is not used; the weight is ignored for themes currently. + // The value is not used; the weight is ignored for themes currently. Do + // not check schema when saving the configuration. $extension_config ->set("theme.$key", 0) - ->save(); + ->save(TRUE); // Add the theme to the current list. // @todo Remove all code that relies on $status property. @@ -358,7 +359,9 @@ class ThemeHandler implements ThemeHandlerInterface { $this->configManager->uninstall('theme', $key); } - $extension_config->save(); + // Don't check schema when uninstalling a theme since we are only clearing + // keys. + $extension_config->save(TRUE); $this->state->set('system.theme.data', $current_theme_data); $this->resetSystem(); diff --git a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php index 77551874f6cb..32862d113557 100644 --- a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php +++ b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php @@ -28,6 +28,20 @@ use Drupal\Core\Field\FieldException; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "field_name", + * "entity_type", + * "bundle", + * "label", + * "description", + * "required", + * "translatable", + * "default_value", + * "default_value_callback", + * "settings", + * "field_type", * } * ) */ diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php index 0354e25491fc..2ad8dc50f58e 100644 --- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php +++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php @@ -260,14 +260,14 @@ class SiteConfigureForm extends ConfigFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { $this->config('system.site') - ->set('name', $form_state->getValue('site_name')) - ->set('mail', $form_state->getValue('site_mail')) - ->save(); + ->set('name', (string) $form_state->getValue('site_name')) + ->set('mail', (string) $form_state->getValue('site_mail')) + ->save(TRUE); $this->config('system.date') - ->set('timezone.default', $form_state->getValue('date_default_timezone')) - ->set('country.default', $form_state->getValue('site_default_country')) - ->save(); + ->set('timezone.default', (string) $form_state->getValue('date_default_timezone')) + ->set('country.default', (string) $form_state->getValue('site_default_country')) + ->save(TRUE); $account_values = $form_state->getValue('account'); @@ -281,7 +281,7 @@ class SiteConfigureForm extends ConfigFormBase { if ($update_status_module[2]) { // Reset the configuration factory so it is updated with the new module. $this->resetConfigFactory(); - $this->config('update.settings')->set('notification.emails', array($account_values['mail']))->save(); + $this->config('update.settings')->set('notification.emails', array($account_values['mail']))->save(TRUE); } } diff --git a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php index a52601cdd79d..d09f7146e7c6 100644 --- a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php +++ b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php @@ -130,20 +130,29 @@ class StaticMenuLinkOverrides implements StaticMenuLinkOverridesInterface { public function saveOverride($id, array $definition) { // Only allow to override a specific subset of the keys. $expected = array( - 'menu_name' => 1, - 'parent' => 1, - 'weight' => 1, - 'expanded' => 1, - 'enabled' => 1, + 'menu_name' => '', + 'parent' => '', + 'weight' => 0, + 'expanded' => FALSE, + 'enabled' => FALSE, ); // Filter the overrides to only those that are expected. $definition = array_intersect_key($definition, $expected); + // Ensure all values are set. + $definition = $definition + $expected; if ($definition) { + // Cast keys to avoid config schema during save. + $definition['menu_name'] = (string) $definition['menu_name']; + $definition['parent'] = (string) $definition['parent']; + $definition['weight'] = (int) $definition['weight']; + $definition['expanded'] = (bool) $definition['expanded']; + $definition['enabled'] = (bool) $definition['enabled']; + $id = static::encodeId($id); $all_overrides = $this->getConfig()->get('definitions'); // Combine with any existing data. $all_overrides[$id] = $definition + $this->loadOverride($id); - $this->getConfig()->set('definitions', $all_overrides)->save(); + $this->getConfig()->set('definitions', $all_overrides)->save(TRUE); } return array_keys($definition); } diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php index 4af2f80be2d8..019f99752c4c 100644 --- a/core/modules/block/src/Entity/Block.php +++ b/core/modules/block/src/Entity/Block.php @@ -38,6 +38,16 @@ use Drupal\Core\Entity\EntityStorageInterface; * links = { * "delete-form" = "/admin/structure/block/manage/{block}/delete", * "edit-form" = "/admin/structure/block/manage/{block}" + * }, + * config_export = { + * "id", + * "theme", + * "region", + * "weight", + * "provider", + * "plugin", + * "settings", + * "visibility", * } * ) */ diff --git a/core/modules/block_content/src/Entity/BlockContentType.php b/core/modules/block_content/src/Entity/BlockContentType.php index 81b64e90491a..84948144bbef 100644 --- a/core/modules/block_content/src/Entity/BlockContentType.php +++ b/core/modules/block_content/src/Entity/BlockContentType.php @@ -38,6 +38,12 @@ use Drupal\block_content\BlockContentTypeInterface; * "delete-form" = "/admin/structure/block/block-content/manage/{block_content_type}/delete", * "edit-form" = "/admin/structure/block/block-content/manage/{block_content_type}", * "collection" = "/admin/structure/block/block-content/types", + * }, + * config_export = { + * "id", + * "label", + * "revision", + * "description", * } * ) */ diff --git a/core/modules/book/config/install/node.type.book.yml b/core/modules/book/config/install/node.type.book.yml index 1a5cc1612909..a5076b2107ba 100644 --- a/core/modules/book/config/install/node.type.book.yml +++ b/core/modules/book/config/install/node.type.book.yml @@ -1,6 +1,8 @@ langcode: en status: true dependencies: + module: + - book enforced: module: - book diff --git a/core/modules/comment/src/Entity/CommentType.php b/core/modules/comment/src/Entity/CommentType.php index fb4144284b7e..94fd193bb450 100644 --- a/core/modules/comment/src/Entity/CommentType.php +++ b/core/modules/comment/src/Entity/CommentType.php @@ -38,6 +38,12 @@ use Drupal\comment\CommentTypeInterface; * "edit-form" = "/admin/structure/comment/manage/{comment_type}", * "add-form" = "/admin/structure/comment/types/add", * "collection" = "/admin/structure/comment/types", + * }, + * config_export = { + * "id", + * "label", + * "target_entity_type_id", + * "description", * } * ) */ diff --git a/core/modules/config/src/Tests/ConfigCRUDTest.php b/core/modules/config/src/Tests/ConfigCRUDTest.php index 268df44b421a..158e4a7fbc03 100644 --- a/core/modules/config/src/Tests/ConfigCRUDTest.php +++ b/core/modules/config/src/Tests/ConfigCRUDTest.php @@ -275,6 +275,14 @@ class ConfigCRUDTest extends KernelTestBase { $this->assertIdentical($config->get(), $data); $this->assertIdentical($storage->read($name), $data); + // Test that schema type enforcement can be overridden by trusting the data. + $this->assertIdentical(99, $config->get('int')); + $config->set('int', '99')->save(TRUE); + $this->assertIdentical('99', $config->get('int')); + // Test that re-saving without testing the data enforces the schema type. + $config->save(); + $this->assertIdentical($data, $config->get()); + // Test that setting an unsupported type for a config object with a schema // fails. try { diff --git a/core/modules/config/src/Tests/ConfigEntityUnitTest.php b/core/modules/config/src/Tests/ConfigEntityUnitTest.php index 164b07db01ab..f96a57646b0a 100644 --- a/core/modules/config/src/Tests/ConfigEntityUnitTest.php +++ b/core/modules/config/src/Tests/ConfigEntityUnitTest.php @@ -17,6 +17,15 @@ use Drupal\simpletest\KernelTestBase; */ class ConfigEntityUnitTest extends KernelTestBase { + /** + * Exempt from strict schema checking. + * + * @see \Drupal\Core\Config\Testing\ConfigSchemaChecker + * + * @var bool + */ + protected $strictConfigSchema = FALSE; + /** * Modules to enable. * @@ -89,6 +98,20 @@ class ConfigEntityUnitTest extends KernelTestBase { foreach ($entities as $entity) { $this->assertIdentical($entity->get('style'), $style, 'The loaded entity has the correct style value specified.'); } + + // Test that schema type enforcement can be overridden by trusting the data. + $entity = $this->storage->create(array( + 'id' => $this->randomMachineName(), + 'label' => $this->randomString(), + 'style' => 999 + )); + $entity->save(); + $this->assertIdentical('999', $entity->style); + $entity->style = 999; + $entity->trustData()->save(); + $this->assertIdentical(999, $entity->style); + $entity->save(); + $this->assertIdentical('999', $entity->style); } } diff --git a/core/modules/config/src/Tests/ConfigInstallTest.php b/core/modules/config/src/Tests/ConfigInstallTest.php index 00ec4fabf47b..2d0954826ca7 100644 --- a/core/modules/config/src/Tests/ConfigInstallTest.php +++ b/core/modules/config/src/Tests/ConfigInstallTest.php @@ -53,7 +53,7 @@ class ConfigInstallTest extends KernelTestBase { // Ensure that schema provided by modules that are not installed is not // available. - $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.schema_in_install'), 'Configuration schema for config_schema_test.schema_in_install does not exist.'); + $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.'); // Install the test module. $this->installModules(array('config_test')); @@ -80,16 +80,12 @@ class ConfigInstallTest extends KernelTestBase { $this->installConfig(array('config_schema_test')); // After module installation the new schema should exist. - $this->assertTrue(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.schema_in_install'), 'Configuration schema for config_schema_test.schema_in_install exists.'); - - // Ensure that data type casting is applied during config installation. - $config = $this->config('config_schema_test.schema_in_install'); - $this->assertIdentical($config->get('integer'), 1); + $this->assertTrue(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema exists.'); // Test that uninstalling configuration removes configuration schema. $this->config('core.extension')->set('module', array())->save(); \Drupal::service('config.manager')->uninstall('module', 'config_test'); - $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.schema_in_install'), 'Configuration schema for config_schema_test.schema_in_install does not exist.'); + $this->assertFalse(\Drupal::service('config.typed')->hasConfigSchema('config_schema_test.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.'); } /** diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php index 8a8f649873f2..11865ef66cff 100644 --- a/core/modules/config/src/Tests/ConfigSchemaTest.php +++ b/core/modules/config/src/Tests/ConfigSchemaTest.php @@ -209,6 +209,7 @@ class ConfigSchemaTest extends KernelTestBase { $this->assertEqual($definition, $expected, 'Retrieved the right metadata for the first effect of image.style.medium'); + $a = \Drupal::config('config_test.dynamic.third_party'); $test = \Drupal::service('config.typed')->get('config_test.dynamic.third_party')->get('third_party_settings.config_schema_test'); $definition = $test->getDataDefinition()->toArray(); $expected = array(); diff --git a/core/modules/config/tests/config_schema_test/config/install/config_schema_test.schema_in_install.yml b/core/modules/config/tests/config_schema_test/config/install/config_schema_test.schema_in_install.yml deleted file mode 100644 index 2ae0ace719b4..000000000000 --- a/core/modules/config/tests/config_schema_test/config/install/config_schema_test.schema_in_install.yml +++ /dev/null @@ -1 +0,0 @@ -integer: '1' diff --git a/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml index 7c18496baf5d..a41dd39a6dfd 100644 --- a/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml +++ b/core/modules/config/tests/config_schema_test/config/schema/config_schema_test.schema.yml @@ -125,14 +125,6 @@ config_schema_test.schema_data_types: sequence: - type: boolean -config_schema_test.schema_in_install: - label: 'Schema test data with parenting' - type: config_object - mapping: - integer: - type: integer - label: 'Integer' - config_schema_test_integer: type: integer label: 'Config test integer' diff --git a/core/modules/config/tests/config_test/config/install/config_test.types.yml b/core/modules/config/tests/config_test/config/install/config_test.types.yml index 060a2b0172b3..6c27522a6b01 100644 --- a/core/modules/config/tests/config_test/config/install/config_test.types.yml +++ b/core/modules/config/tests/config_test/config/install/config_test.types.yml @@ -2,7 +2,7 @@ array: [] boolean: true exp: 1.2e+34 float: 3.14159 -float_as_integer: 1 +float_as_integer: !!float 1 hex: 0xC int: 99 octal: 0775 diff --git a/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override.yml b/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override.yml index 972119095caf..af26b07b98d8 100644 --- a/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override.yml +++ b/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override.yml @@ -3,4 +3,4 @@ id: override label: Default weight: 0 protected_property: Default -status: 1 +status: true diff --git a/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override_unmet.yml b/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override_unmet.yml index 7fa7ae40d319..82a9c3c382af 100644 --- a/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override_unmet.yml +++ b/core/modules/config/tests/config_test/config/optional/config_test.dynamic.override_unmet.yml @@ -4,7 +4,7 @@ id: override_unmet label: Default weight: 0 protected_property: Default -status: 1 +status: true dependencies: module: - tour diff --git a/core/modules/contact/src/Entity/ContactForm.php b/core/modules/contact/src/Entity/ContactForm.php index c0cf26ad4aa1..0967c907e328 100644 --- a/core/modules/contact/src/Entity/ContactForm.php +++ b/core/modules/contact/src/Entity/ContactForm.php @@ -36,6 +36,13 @@ use Drupal\contact\ContactFormInterface; * "delete-form" = "/admin/structure/contact/manage/{contact_form}/delete", * "edit-form" = "/admin/structure/contact/manage/{contact_form}", * "collection" = "/admin/structure/contact", + * }, + * config_export = { + * "id", + * "label", + * "recipients", + * "reply", + * "weight", * } * ) */ diff --git a/core/modules/editor/src/Entity/Editor.php b/core/modules/editor/src/Entity/Editor.php index 60cdf5a4e928..159c9b13f96c 100644 --- a/core/modules/editor/src/Entity/Editor.php +++ b/core/modules/editor/src/Entity/Editor.php @@ -18,6 +18,12 @@ use Drupal\editor\EditorInterface; * label = @Translation("Text Editor"), * entity_keys = { * "id" = "format" + * }, + * config_export = { + * "format", + * "editor", + * "settings", + * "image_upload", * } * ) */ diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php index ad5127bf15e1..20d168eb787b 100644 --- a/core/modules/field/src/Entity/FieldConfig.php +++ b/core/modules/field/src/Entity/FieldConfig.php @@ -28,6 +28,20 @@ use Drupal\field\FieldConfigInterface; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "field_name", + * "entity_type", + * "bundle", + * "label", + * "description", + * "required", + * "translatable", + * "default_value", + * "default_value_callback", + * "settings", + * "field_type", * } * ) */ diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php index ca77119a35e2..97db63f60d0d 100644 --- a/core/modules/field/src/Entity/FieldStorageConfig.php +++ b/core/modules/field/src/Entity/FieldStorageConfig.php @@ -30,6 +30,19 @@ use Drupal\field\FieldStorageConfigInterface; * entity_keys = { * "id" = "id", * "label" = "id" + * }, + * config_export = { + * "id", + * "field_name", + * "entity_type", + * "type", + * "settings", + * "module", + * "locked", + * "cardinality", + * "translatable", + * "indexes", + * "persist_with_no_fields", * } * ) */ diff --git a/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php b/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php index 49d34e2be996..2bce97d08151 100644 --- a/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php +++ b/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php @@ -22,7 +22,7 @@ class FieldConfigEntityUnitTest extends UnitTestCase { /** * The entity type used for testing. * - * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $entityType; diff --git a/core/modules/field/tests/src/Unit/FieldStorageConfigEntityUnitTest.php b/core/modules/field/tests/src/Unit/FieldStorageConfigEntityUnitTest.php index cd05b9b9991f..424424a7bd5a 100644 --- a/core/modules/field/tests/src/Unit/FieldStorageConfigEntityUnitTest.php +++ b/core/modules/field/tests/src/Unit/FieldStorageConfigEntityUnitTest.php @@ -18,13 +18,6 @@ use Drupal\Tests\UnitTestCase; */ class FieldStorageConfigEntityUnitTest extends UnitTestCase { - /** - * The entity type used for testing. - * - * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $entityType; - /** * The entity manager used for testing. * @@ -64,7 +57,7 @@ class FieldStorageConfigEntityUnitTest extends UnitTestCase { */ public function testCalculateDependencies() { // Create a mock entity type for FieldStorageConfig. - $fieldStorageConfigentityType = $this->getMock('\Drupal\Core\Entity\EntityTypeInterface'); + $fieldStorageConfigentityType = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityTypeInterface'); $fieldStorageConfigentityType->expects($this->any()) ->method('getProvider') ->will($this->returnValue('field')); diff --git a/core/modules/field_ui/src/Tests/EntityDisplayTest.php b/core/modules/field_ui/src/Tests/EntityDisplayTest.php index 495b8e778540..926f1c9b24fb 100644 --- a/core/modules/field_ui/src/Tests/EntityDisplayTest.php +++ b/core/modules/field_ui/src/Tests/EntityDisplayTest.php @@ -116,10 +116,10 @@ class EntityDisplayTest extends KernelTestBase { $display->setComponent('component_3'); $display->setComponent('component_1'); $display->setComponent('component_2'); - $display->removeComponent('name'); $display->save(); $components = array_keys($display->getComponents()); - $expected = array ( 0 => 'component_1', 1 => 'component_2', 2 => 'component_3',); + // The name field is not configurable so will be added automatically. + $expected = array ( 0 => 'component_1', 1 => 'component_2', 2 => 'component_3', 'name'); $this->assertIdentical($components, $expected); } diff --git a/core/modules/file/config/optional/views.view.files.yml b/core/modules/file/config/optional/views.view.files.yml index 23bfd821e54a..fc1b54022bfc 100644 --- a/core/modules/file/config/optional/views.view.files.yml +++ b/core/modules/file/config/optional/views.view.files.yml @@ -236,7 +236,7 @@ display: delta_first_last: false multi_type: separator separator: ', ' - field_api_classes: 0 + field_api_classes: false plugin_id: field entity_type: file entity_field: filename diff --git a/core/modules/filter/src/Entity/FilterFormat.php b/core/modules/filter/src/Entity/FilterFormat.php index 6df0f97a4c6c..cf61f7f787ac 100644 --- a/core/modules/filter/src/Entity/FilterFormat.php +++ b/core/modules/filter/src/Entity/FilterFormat.php @@ -41,6 +41,13 @@ use Drupal\filter\Plugin\FilterInterface; * links = { * "edit-form" = "/admin/config/content/formats/manage/{filter_format}", * "disable" = "/admin/config/content/formats/manage/{filter_format}/disable" + * }, + * config_export = { + * "name", + * "format", + * "weight", + * "roles", + * "filters", * } * ) */ diff --git a/core/modules/forum/config/install/node.type.forum.yml b/core/modules/forum/config/install/node.type.forum.yml index 8ed965df3fb6..b03afe0d023d 100644 --- a/core/modules/forum/config/install/node.type.forum.yml +++ b/core/modules/forum/config/install/node.type.forum.yml @@ -1,6 +1,8 @@ langcode: en status: true dependencies: + module: + - forum enforced: module: - forum diff --git a/core/modules/forum/config/install/taxonomy.vocabulary.forums.yml b/core/modules/forum/config/install/taxonomy.vocabulary.forums.yml index 951e4a354db4..cfbcca558306 100644 --- a/core/modules/forum/config/install/taxonomy.vocabulary.forums.yml +++ b/core/modules/forum/config/install/taxonomy.vocabulary.forums.yml @@ -1,6 +1,8 @@ langcode: en status: true dependencies: + module: + - forum enforced: module: - forum diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php index a3c7ab534029..a05d3a88120e 100644 --- a/core/modules/image/src/Entity/ImageStyle.php +++ b/core/modules/image/src/Entity/ImageStyle.php @@ -48,6 +48,11 @@ use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; * "edit-form" = "/admin/config/media/image-styles/manage/{image_style}", * "delete-form" = "/admin/config/media/image-styles/manage/{image_style}/delete", * "collection" = "/admin/config/media/image-styles", + * }, + * config_export = { + * "name", + * "label", + * "effects", * } * ) */ diff --git a/core/modules/language/src/Config/LanguageConfigOverride.php b/core/modules/language/src/Config/LanguageConfigOverride.php index 5be48ad5d22c..b673f3475674 100644 --- a/core/modules/language/src/Config/LanguageConfigOverride.php +++ b/core/modules/language/src/Config/LanguageConfigOverride.php @@ -50,13 +50,16 @@ class LanguageConfigOverride extends StorableConfigBase { /** * {@inheritdoc} */ - public function save() { - // @todo Use configuration schema to validate. - // https://drupal.org/node/2270399 - // Perform basic data validation. - foreach ($this->data as $key => $value) { - $this->validateValue($key, $value); + public function save($has_trusted_data = FALSE) { + if (!$has_trusted_data) { + // @todo Use configuration schema to validate. + // https://drupal.org/node/2270399 + // Perform basic data validation. + foreach ($this->data as $key => $value) { + $this->validateValue($key, $value); + } } + $this->storage->write($this->name, $this->data); // Invalidate the cache tags not only when updating, but also when creating, // because a language config override object uses the same cache tag as the diff --git a/core/modules/node/config/install/system.action.node_promote_action.yml b/core/modules/node/config/install/system.action.node_promote_action.yml index b1b4f05ef373..4b3a9ae1608c 100644 --- a/core/modules/node/config/install/system.action.node_promote_action.yml +++ b/core/modules/node/config/install/system.action.node_promote_action.yml @@ -4,3 +4,6 @@ status: true langcode: en type: node plugin: node_promote_action +dependencies: + module: + - node diff --git a/core/modules/node/config/install/system.action.node_publish_action.yml b/core/modules/node/config/install/system.action.node_publish_action.yml index e882bf317f4b..af0b82c5c845 100644 --- a/core/modules/node/config/install/system.action.node_publish_action.yml +++ b/core/modules/node/config/install/system.action.node_publish_action.yml @@ -4,3 +4,6 @@ status: true langcode: en type: node plugin: node_publish_action +dependencies: + module: + - node diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php index 238ae8f7b021..2d8ac1516745 100644 --- a/core/modules/node/src/Entity/NodeType.php +++ b/core/modules/node/src/Entity/NodeType.php @@ -37,6 +37,15 @@ use Drupal\node\NodeTypeInterface; * "edit-form" = "/admin/structure/types/manage/{node_type}", * "delete-form" = "/admin/structure/types/manage/{node_type}/delete", * "collection" = "/admin/structure/types", + * }, + * config_export = { + * "name", + * "type", + * "description", + * "help", + * "new_revision", + * "preview_mode", + * "display_submitted", * } * ) */ diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php index 8fd6e290b810..9ce7cb0612db 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php @@ -110,4 +110,11 @@ class ListFloatItem extends ListItemBase { return $values; } + /** + * {@inheritdoc} + */ + protected static function castAllowedValue($value) { + return (float) $value; + } + } diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php index 59923867ea7e..2ded4ca9642c 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php @@ -73,4 +73,11 @@ class ListIntegerItem extends ListItemBase { } } + /** + * {@inheritdoc} + */ + protected static function castAllowedValue($value) { + return (int) $value; + } + } diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php index bdf063a4c025..9b785d862ee1 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php @@ -314,11 +314,24 @@ abstract class ListItemBase extends FieldItemBase implements OptionsProviderInte $label = static::structureAllowedValues($label); } $structured_values[] = array( - 'value' => $value, + 'value' => static::castAllowedValue($value), 'label' => $label, ); } return $structured_values; } + /** + * Converts a value to the correct type. + * + * @param mixed $value + * The value to cast. + * + * @return mixed + * The casted value. + */ + protected static function castAllowedValue($value) { + return $value; + } + } diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php index f3bf401134a0..da308109ff3d 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php @@ -75,4 +75,11 @@ class ListStringItem extends ListItemBase { } } + /** + * {@inheritdoc} + */ + protected static function castAllowedValue($value) { + return (string) $value; + } + } diff --git a/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml b/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml index f355b2ed9487..1d02c6161eb0 100644 --- a/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml +++ b/core/modules/options/tests/options_config_install_test/config/install/field.storage.node.field_options_float.yml @@ -11,7 +11,7 @@ type: list_float settings: allowed_values: - - value: 0 + value: !!float 0 label: Zero - value: 0.5 diff --git a/core/modules/rdf/src/Entity/RdfMapping.php b/core/modules/rdf/src/Entity/RdfMapping.php index 577cbe7adced..0a32009f1623 100644 --- a/core/modules/rdf/src/Entity/RdfMapping.php +++ b/core/modules/rdf/src/Entity/RdfMapping.php @@ -20,6 +20,13 @@ use Drupal\rdf\RdfMappingInterface; * config_prefix = "mapping", * entity_keys = { * "id" = "id" + * }, + * config_export = { + * "id", + * "targetEntityType", + * "bundle", + * "types", + * "fieldMappings", * } * ) */ diff --git a/core/modules/search/src/Entity/SearchPage.php b/core/modules/search/src/Entity/SearchPage.php index 0f583c750db8..fcce23d96e72 100644 --- a/core/modules/search/src/Entity/SearchPage.php +++ b/core/modules/search/src/Entity/SearchPage.php @@ -47,6 +47,14 @@ use Drupal\search\SearchPageInterface; * "label" = "label", * "weight" = "weight", * "status" = "status" + * }, + * config_export = { + * "id", + * "label", + * "path", + * "weight", + * "plugin", + * "configuration", * } * ) */ diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install index 2a90306e34a0..73986b817829 100644 --- a/core/modules/shortcut/shortcut.install +++ b/core/modules/shortcut/shortcut.install @@ -53,7 +53,7 @@ function shortcut_install() { // Theme settings are not configuration entities and cannot depend on modules // so to set a module-specific setting, we need to set it with logic. if (\Drupal::service('theme_handler')->themeExists('seven')) { - \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save(); + \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save(TRUE); } } @@ -64,6 +64,6 @@ function shortcut_uninstall() { // Theme settings are not configuration entities and cannot depend on modules // so to unset a module-specific setting, we need to unset it with logic. if (\Drupal::service('theme_handler')->themeExists('seven')) { - \Drupal::configFactory()->getEditable('seven.settings')->clear('third_party_settings.shortcut.module_link')->save(); + \Drupal::configFactory()->getEditable('seven.settings')->clear('third_party_settings.shortcut.module_link')->save(TRUE); } } diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module index b406bc5c3c30..7fdadd1489b5 100644 --- a/core/modules/shortcut/shortcut.module +++ b/core/modules/shortcut/shortcut.module @@ -415,7 +415,7 @@ function shortcut_themes_installed($theme_list) { // Theme settings are not configuration entities and cannot depend on modules // so to set a module-specific setting, we need to set it with logic. if (\Drupal::moduleHandler()->moduleExists('shortcut')) { - \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save(); + \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save(TRUE); } } } diff --git a/core/modules/shortcut/src/Entity/ShortcutSet.php b/core/modules/shortcut/src/Entity/ShortcutSet.php index 692e3abea5cc..52e3ecce0297 100644 --- a/core/modules/shortcut/src/Entity/ShortcutSet.php +++ b/core/modules/shortcut/src/Entity/ShortcutSet.php @@ -40,6 +40,10 @@ use Drupal\shortcut\ShortcutSetInterface; * "delete-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}/delete", * "edit-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}", * "collection" = "/admin/config/user-interface/shortcut", + * }, + * config_export = { + * "id", + * "label", * } * ) */ diff --git a/core/modules/system/src/Entity/Action.php b/core/modules/system/src/Entity/Action.php index ca3d8cfce8f6..b5a0f19bca56 100644 --- a/core/modules/system/src/Entity/Action.php +++ b/core/modules/system/src/Entity/Action.php @@ -24,6 +24,13 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "label", + * "type", + * "plugin", + * "configuration", * } * ) */ diff --git a/core/modules/system/src/Entity/Menu.php b/core/modules/system/src/Entity/Menu.php index bf5d77d57435..fa738f30998b 100644 --- a/core/modules/system/src/Entity/Menu.php +++ b/core/modules/system/src/Entity/Menu.php @@ -24,6 +24,12 @@ use Drupal\system\MenuInterface; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "label", + * "description", + * "locked", * } * ) */ diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 702753e923cb..6c3db4608c93 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -665,7 +665,7 @@ function system_install() { if (!$site->get('name')) { $site->set('name', 'Drupal'); } - $site->save(); + $site->save(TRUE); } /** diff --git a/core/modules/system/tests/themes/test_basetheme/config/install/core.date_format.fancy.yml b/core/modules/system/tests/themes/test_basetheme/config/install/core.date_format.fancy.yml index 05d5e2774e87..fc76e730b9c3 100644 --- a/core/modules/system/tests/themes/test_basetheme/config/install/core.date_format.fancy.yml +++ b/core/modules/system/tests/themes/test_basetheme/config/install/core.date_format.fancy.yml @@ -8,6 +8,8 @@ langcode: en locked: false pattern: 'U' dependencies: + theme: + - test_basetheme enforced: theme: - test_basetheme diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php index 7b2def3c478b..2855c6596c51 100644 --- a/core/modules/taxonomy/src/Entity/Vocabulary.php +++ b/core/modules/taxonomy/src/Entity/Vocabulary.php @@ -41,6 +41,13 @@ use Drupal\taxonomy\VocabularyInterface; * "overview-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview", * "edit-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}", * "collection" = "/admin/structure/taxonomy", + * }, + * config_export = { + * "name", + * "vid", + * "description", + * "hierarchy", + * "weight", * } * ) */ diff --git a/core/modules/tour/src/Entity/Tour.php b/core/modules/tour/src/Entity/Tour.php index d50caa982d62..15357e0d658b 100644 --- a/core/modules/tour/src/Entity/Tour.php +++ b/core/modules/tour/src/Entity/Tour.php @@ -24,6 +24,13 @@ use Drupal\tour\TourInterface; * entity_keys = { * "id" = "id", * "label" = "label" + * }, + * config_export = { + * "id", + * "label", + * "module", + * "routes", + * "tips", * } * ) */ diff --git a/core/modules/user/config/optional/views.view.user_admin_people.yml b/core/modules/user/config/optional/views.view.user_admin_people.yml index 8be9b7ec5145..004471c5e1bd 100644 --- a/core/modules/user/config/optional/views.view.user_admin_people.yml +++ b/core/modules/user/config/optional/views.view.user_admin_people.yml @@ -567,7 +567,7 @@ display: delta_first_last: false multi_type: separator separator: ', ' - field_api_classes: 0 + field_api_classes: false plugin_id: field entity_type: user entity_field: mail diff --git a/core/modules/user/src/Entity/Role.php b/core/modules/user/src/Entity/Role.php index 9216ad842b91..b997e69b83bc 100644 --- a/core/modules/user/src/Entity/Role.php +++ b/core/modules/user/src/Entity/Role.php @@ -40,6 +40,13 @@ use Drupal\user\RoleInterface; * "edit-form" = "/admin/people/roles/manage/{user_role}", * "edit-permissions-form" = "/admin/people/permissions/{user_role}", * "collection" = "/admin/people/roles", + * }, + * config_export = { + * "id", + * "label", + * "weight", + * "is_admin", + * "permissions", * } * ) */ diff --git a/core/modules/user/user.module b/core/modules/user/user.module index f35f5470691c..d175edf042c3 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -988,7 +988,7 @@ function user_user_role_insert(RoleInterface $role) { ), 'plugin' => 'user_add_role_action', )); - $action->save(); + $action->trustData()->save(); } $remove_id = 'user_remove_role_action.' . $role->id(); if (!entity_load('action', $remove_id)) { @@ -1001,7 +1001,7 @@ function user_user_role_insert(RoleInterface $role) { ), 'plugin' => 'user_remove_role_action', )); - $action->save(); + $action->trustData()->save(); } } @@ -1149,7 +1149,7 @@ function user_role_grant_permissions($rid, array $permissions = array()) { foreach ($permissions as $permission) { $role->grantPermission($permission); } - $role->save(); + $role->trustData()->save(); } } @@ -1170,7 +1170,7 @@ function user_role_revoke_permissions($rid, array $permissions = array()) { foreach ($permissions as $permission) { $role->revokePermission($permission); } - $role->save(); + $role->trustData()->save(); } /** diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php index 34b4ab093d3b..b7188c5b71cc 100644 --- a/core/modules/views/src/Entity/View.php +++ b/core/modules/views/src/Entity/View.php @@ -29,6 +29,17 @@ use Drupal\views\ViewEntityInterface; * "id" = "id", * "label" = "label", * "status" = "status" + * }, + * config_export = { + * "id", + * "label", + * "module", + * "description", + * "tag", + * "base_table", + * "base_field", + * "core", + * "display", * } * ) */ diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index a45d39abd8fd..d683426f5243 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -2293,7 +2293,7 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte $cache_plugin->alterCacheMetadata($is_cacheable, $cache_contexts); } - return [$is_cacheable, $cache_contexts]; + return [(bool) $is_cacheable, $cache_contexts]; } /** diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php index 8b5569e4d036..75bbbdfb0150 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -1285,4 +1285,18 @@ class ViewUI implements ViewEntityInterface { return $this->storage->getThirdPartyProviders(); } + /** + * {@inheritdoc} + */ + public function trustData() { + return $this->storage->trustData(); + } + + /** + * {@inheritdoc} + */ + public function hasTrustedData() { + return $this->storage->hasTrustedData(); + } + } diff --git a/core/profiles/minimal/minimal.install b/core/profiles/minimal/minimal.install index a8baf07906b3..d30cb3ba5b67 100644 --- a/core/profiles/minimal/minimal.install +++ b/core/profiles/minimal/minimal.install @@ -13,8 +13,8 @@ */ function minimal_install() { // Disable the user pictures on nodes. - \Drupal::configFactory()->getEditable('system.theme.global')->set('features.node_user_picture', FALSE)->save(); + \Drupal::configFactory()->getEditable('system.theme.global')->set('features.node_user_picture', FALSE)->save(TRUE); // Allow visitor account creation, but with administrative approval. - \Drupal::configFactory()->getEditable('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save(); + \Drupal::configFactory()->getEditable('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save(TRUE); } diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install index b5e2b6356d49..000ffa4c7411 100644 --- a/core/profiles/standard/standard.install +++ b/core/profiles/standard/standard.install @@ -23,11 +23,11 @@ function standard_install() { \Drupal::service('entity.definition_update_manager')->applyUpdates(); // Set front page to "node". - \Drupal::configFactory()->getEditable('system.site')->set('page.front', 'node')->save(); + \Drupal::configFactory()->getEditable('system.site')->set('page.front', 'node')->save(TRUE); // Allow visitor account creation with administrative approval. $user_settings = \Drupal::configFactory()->getEditable('user.settings'); - $user_settings->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save(); + $user_settings->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save(TRUE); // Enable default permissions for system roles. user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('access comments')); @@ -41,7 +41,7 @@ function standard_install() { // Enable the Contact link in the footer menu. /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */ $menu_link_manager = \Drupal::service('plugin.manager.menu.link'); - $menu_link_manager->updateDefinition('contact.site_page', array('enabled' => 1)); + $menu_link_manager->updateDefinition('contact.site_page', array('enabled' => TRUE)); user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('access site-wide contact form')); user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, array('access site-wide contact form')); @@ -67,5 +67,5 @@ function standard_install() { $shortcut->save(); // Enable the admin theme. - \Drupal::configFactory()->getEditable('node.settings')->set('use_admin_theme', '1')->save(); + \Drupal::configFactory()->getEditable('node.settings')->set('use_admin_theme', TRUE)->save(TRUE); } diff --git a/core/profiles/standard/standard.profile b/core/profiles/standard/standard.profile index ad69906d6d37..030b92a075ae 100644 --- a/core/profiles/standard/standard.profile +++ b/core/profiles/standard/standard.profile @@ -23,5 +23,5 @@ function standard_form_install_configure_form_alter(&$form, FormStateInterface $ */ function standard_form_install_configure_submit($form, FormStateInterface $form_state) { $site_mail = $form_state->getValue('site_mail'); - ContactForm::load('feedback')->setRecipients([$site_mail])->save(); + ContactForm::load('feedback')->setRecipients([$site_mail])->trustData()->save(); } diff --git a/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override.yml b/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override.yml index 4a54a333c049..e0d67e02d883 100644 --- a/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override.yml +++ b/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override.yml @@ -2,7 +2,7 @@ id: override label: Override weight: 0 protected_property: Default -status: 1 +status: true dependencies: module: - tour diff --git a/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override_unmet.yml b/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override_unmet.yml index f20365f7d268..d4e755dbcb93 100644 --- a/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override_unmet.yml +++ b/core/profiles/testing_config_overrides/config/optional/config_test.dynamic.override_unmet.yml @@ -2,7 +2,7 @@ id: override_unmet label: Override weight: 0 protected_property: Default -status: 1 +status: true dependencies: module: - dblog diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php index a0e043b4d339..b654077453f5 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php @@ -28,7 +28,7 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { /** * The entity type used for testing. * - * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $entityType; @@ -463,9 +463,52 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { * @covers ::toArray */ public function testToArray() { + $this->typedConfigManager->expects($this->never()) + ->method('getDefinition'); + $this->entityType->expects($this->any()) + ->method('getPropertiesToExport') + ->willReturn(['id' => 'configId', 'dependencies' => 'dependencies']); + $properties = $this->entity->toArray(); + $this->assertInternalType('array', $properties); + $this->assertEquals(array('configId' => $this->entity->id(), 'dependencies' => array()), $properties); + } + + /** + * @covers ::toArray + */ + public function testToArrayIdKey() { + $entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [[], $this->entityTypeId], '', TRUE, TRUE, TRUE, ['id', 'get']); + $entity->expects($this->atLeastOnce()) + ->method('id') + ->willReturn($this->id); + $entity->expects($this->once()) + ->method('get') + ->with('dependencies') + ->willReturn([]); + $this->typedConfigManager->expects($this->never()) + ->method('getDefinition'); + $this->entityType->expects($this->any()) + ->method('getPropertiesToExport') + ->willReturn(['id' => 'configId', 'dependencies' => 'dependencies']); + $this->entityType->expects($this->once()) + ->method('getKey') + ->with('id') + ->willReturn('id'); + $properties = $entity->toArray(); + $this->assertInternalType('array', $properties); + $this->assertEquals(['configId' => $entity->id(), 'dependencies' => []], $properties); + } + + /** + * @covers ::toArray + */ + public function testToArraySchemaFallback() { $this->typedConfigManager->expects($this->once()) ->method('getDefinition') ->will($this->returnValue(array('mapping' => array('id' => '', 'dependencies' => '')))); + $this->entityType->expects($this->any()) + ->method('getPropertiesToExport') + ->willReturn([]); $properties = $this->entity->toArray(); $this->assertInternalType('array', $properties); $this->assertEquals(array('id' => $this->entity->id(), 'dependencies' => array()), $properties); @@ -477,6 +520,9 @@ class ConfigEntityBaseUnitTest extends UnitTestCase { * @expectedException \Drupal\Core\Config\Schema\SchemaIncompleteException */ public function testToArrayFallback() { + $this->entityType->expects($this->any()) + ->method('getPropertiesToExport') + ->willReturn([]); $this->entity->toArray(); } diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php index 12096baf3ffc..c4413eb91441 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php @@ -22,7 +22,7 @@ class ConfigEntityStorageTest extends UnitTestCase { /** * The entity type. * - * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $entityType; @@ -279,6 +279,9 @@ class ConfigEntityStorageTest extends UnitTestCase { ->method('setData'); $config_object->expects($this->once()) ->method('save'); + $config_object->expects($this->atLeastOnce()) + ->method('get') + ->willReturn([]); $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') @@ -343,6 +346,9 @@ class ConfigEntityStorageTest extends UnitTestCase { ->method('setData'); $config_object->expects($this->once()) ->method('save'); + $config_object->expects($this->atLeastOnce()) + ->method('get') + ->willReturn([]); $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') @@ -408,6 +414,9 @@ class ConfigEntityStorageTest extends UnitTestCase { ->method('setData'); $config_object->expects($this->once()) ->method('save'); + $config_object->expects($this->atLeastOnce()) + ->method('get') + ->willReturn([]); $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') @@ -546,6 +555,9 @@ class ConfigEntityStorageTest extends UnitTestCase { ->will($this->returnValue(TRUE)); $config_object->expects($this->once()) ->method('save'); + $config_object->expects($this->atLeastOnce()) + ->method('get') + ->willReturn([]); $this->cacheTagsInvalidator->expects($this->once()) ->method('invalidateTags') diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php index b427dfc10e4b..524fea0e93b7 100644 --- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php +++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityTypeTest.php @@ -131,4 +131,60 @@ class ConfigEntityTypeTest extends UnitTestCase { ); } + /** + * @covers ::getPropertiesToExport + * + * @dataProvider providerGetPropertiesToExport + */ + public function testGetPropertiesToExport($definition, $expected) { + $entity_type = $this->setUpConfigEntityType($definition); + $properties_to_export = $entity_type->getPropertiesToExport(); + $this->assertSame($expected, $properties_to_export); + + // Ensure the method is idempotent. + $properties_to_export = $entity_type->getPropertiesToExport(); + $this->assertSame($expected, $properties_to_export); + } + + public function providerGetPropertiesToExport() { + $data = []; + $data[] = [ + [], + NULL, + ]; + + $data[] = [ + [ + 'config_export' => [ + 'id', + 'custom_property' => 'customProperty', + ], + ], + [ + 'uuid' => 'uuid', + 'langcode' => 'langcode', + 'status' => 'status', + 'dependencies' => 'dependencies', + 'third_party_settings' => 'third_party_settings', + 'id' => 'id', + 'custom_property' => 'customProperty', + ], + ]; + + $data[] = [ + [ + 'config_export' => [ + 'id', + ], + 'mergedConfigExport' => [ + 'random_key' => 'random_key', + ], + ], + [ + 'random_key' => 'random_key', + ], + ]; + return $data; + } + } diff --git a/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php b/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php index 3f6093317e8b..32d0b3a24873 100644 --- a/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php @@ -114,11 +114,15 @@ class StaticMenuLinkOverridesTest extends UnitTestCase { ->with('definitions') ->will($this->returnValue(array())); - $definition_save_1 = array('definitions' => array('test1' => array('parent' => 'test0'))); + $definition_save_1 = array( + 'definitions' => array( + 'test1' => array('parent' => 'test0', 'menu_name' => '', 'weight' => 0, 'expanded' => FALSE, 'enabled' => FALSE) + ) + ); $definitions_save_2 = array( 'definitions' => array( - 'test1' => array('parent' => 'test0'), - 'test1__la___ma' => array('parent' => 'test1') + 'test1' => array('parent' => 'test0', 'menu_name' => '', 'weight' => 0, 'expanded' => FALSE, 'enabled' => FALSE), + 'test1__la___ma' => array('parent' => 'test1', 'menu_name' => '', 'weight' => 0, 'expanded' => FALSE, 'enabled' => FALSE) ) ); $config->expects($this->at(2))