diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index 51ade6c..8861481 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -203,22 +203,24 @@ public function clear($key) { /** * {@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); + } } } @@ -302,4 +304,5 @@ public function getOriginal($key = '', $apply_overrides = TRUE) { } } } + } diff --git a/core/lib/Drupal/Core/Config/ConfigInstaller.php b/core/lib/Drupal/Core/Config/ConfigInstaller.php index ffdc760..e7fa6ad 100644 --- a/core/lib/Drupal/Core/Config/ConfigInstaller.php +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php @@ -289,11 +289,11 @@ protected function createConfiguration($collection, array $config_to_create) { $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 90837f9..1675931 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php @@ -105,6 +105,8 @@ */ protected $third_party_settings = array(); + protected $trustedData = FALSE; + /** * Overrides Entity::__construct(). */ @@ -324,7 +326,7 @@ public function preSave(EntityStorageInterface $storage) { throw new ConfigDuplicateUUIDException(String::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. @@ -568,4 +570,28 @@ public function isInstallable() { 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 3d688a5..41997cb 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityInterface.php @@ -203,4 +203,25 @@ public function getDependencies(); */ public function isInstallable(); + /** + * Sets that the data should be trusted. + * + * @param bool $trust + * TRUE if the configuration data is trusted, FALSE if not. 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. + * + * @return $this + */ + 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 27da150..aed551a 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php @@ -256,7 +256,7 @@ protected function doSave($id, EntityInterface $entity) { // Retrieve the desired properties and set them in config. $config->setData($this->mapToStorageRecord($entity)); - $config->save(); + $config->save($entity->hasTrustedData()); return $is_new ? SAVED_NEW : SAVED_UPDATED; } diff --git a/core/lib/Drupal/Core/Config/ImmutableConfig.php b/core/lib/Drupal/Core/Config/ImmutableConfig.php index 61e7fdd..d4bdaf5 100644 --- a/core/lib/Drupal/Core/Config/ImmutableConfig.php +++ b/core/lib/Drupal/Core/Config/ImmutableConfig.php @@ -44,7 +44,7 @@ public function clear($key) { /** * {@inheritdoc} */ - public function save() { + public function save($has_trusted_data = FALSE) { throw new ImmutableConfigException(String::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 4af470e..9f08a8f 100644 --- a/core/lib/Drupal/Core/Config/StorableConfigBase.php +++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php @@ -66,11 +66,16 @@ /** * 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 */ - abstract public function save(); + abstract public function save($has_trusted_data = FALSE); /** * Deletes the configuration object. diff --git a/core/modules/book/config/install/node.type.book.yml b/core/modules/book/config/install/node.type.book.yml index 1a5cc16..a5076b2 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/config/src/Tests/ConfigInstallTest.php b/core/modules/config/src/Tests/ConfigInstallTest.php index 9a903a1..d94fade 100644 --- a/core/modules/config/src/Tests/ConfigInstallTest.php +++ b/core/modules/config/src/Tests/ConfigInstallTest.php @@ -20,234 +20,230 @@ */ class ConfigInstallTest extends KernelTestBase { - /** - * {@inheritdoc} - */ - public static $modules = ['system']; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - $this->installSchema('system', ['router']); - - // Ensure the global variable being asserted by this test does not exist; - // a previous test executed in this request/process might have set it. - unset($GLOBALS['hook_config_test']); - } - - /** - * Tests module installation. - */ - function testModuleInstallation() { - $default_config = 'config_test.system'; - $default_configuration_entity = 'config_test.dynamic.dotted.default'; - - // Verify that default module config does not exist before installation yet. - $config = $this->config($default_config); - $this->assertIdentical($config->isNew(), TRUE); - $config = $this->config($default_configuration_entity); - $this->assertIdentical($config->isNew(), TRUE); - - // 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.'); - - // Install the test module. - $this->installModules(array('config_test')); - - // Verify that default module config exists. - \Drupal::configFactory()->reset($default_config); - \Drupal::configFactory()->reset($default_configuration_entity); - $config = $this->config($default_config); - $this->assertIdentical($config->isNew(), FALSE); - $config = $this->config($default_configuration_entity); - $this->assertIdentical($config->isNew(), FALSE); - - // Verify that config_test API hooks were invoked for the dynamic default - // configuration entity. - $this->assertFalse(isset($GLOBALS['hook_config_test']['load'])); - $this->assertTrue(isset($GLOBALS['hook_config_test']['presave'])); - $this->assertTrue(isset($GLOBALS['hook_config_test']['insert'])); - $this->assertFalse(isset($GLOBALS['hook_config_test']['update'])); - $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete'])); - $this->assertFalse(isset($GLOBALS['hook_config_test']['delete'])); - - // Install the schema test module. - $this->enableModules(array('config_schema_test')); - $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); - - // 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.'); - } - - /** - * Tests that collections are ignored if the event does not return anything. - */ - public function testCollectionInstallationNoCollections() { - // Install the test module. - $this->enableModules(array('config_collection_install_test')); - $this->installConfig(array('config_collection_install_test')); - /** @var \Drupal\Core\Config\StorageInterface $active_storage */ - $active_storage = \Drupal::service('config.storage'); - $this->assertEqual(array(), $active_storage->getAllCollectionNames()); - } - - /** - * Tests config objects in collections are installed as expected. - */ - public function testCollectionInstallationCollections() { - $collections = array( - 'another_collection', - 'collection.test1', - 'collection.test2', - ); - // Set the event listener to return three possible collections. - // @see \Drupal\config_collection_install_test\EventSubscriber - \Drupal::state()->set('config_collection_install_test.collection_names', $collections); - // Install the test module. - $this->enableModules(array('config_collection_install_test')); - $this->installConfig(array('config_collection_install_test')); - /** @var \Drupal\Core\Config\StorageInterface $active_storage */ - $active_storage = \Drupal::service('config.storage'); - $this->assertEqual($collections, $active_storage->getAllCollectionNames()); - foreach ($collections as $collection) { - $collection_storage = $active_storage->createCollection($collection); - $data = $collection_storage->read('config_collection_install_test.test'); - $this->assertEqual($collection, $data['collection']); + /** + * {@inheritdoc} + */ + public static $modules = ['system']; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->installSchema('system', ['router']); + + // Ensure the global variable being asserted by this test does not exist; + // a previous test executed in this request/process might have set it. + unset($GLOBALS['hook_config_test']); } - // Tests that clashing configuration in collections is detected. - try { - \Drupal::service('module_installer')->install(['config_collection_clash_install_test']); - $this->fail('Expected PreExistingConfigException not thrown.'); + /** + * Tests module installation. + */ + function testModuleInstallation() { + $default_config = 'config_test.system'; + $default_configuration_entity = 'config_test.dynamic.dotted.default'; + + // Verify that default module config does not exist before installation yet. + $config = $this->config($default_config); + $this->assertIdentical($config->isNew(), TRUE); + $config = $this->config($default_configuration_entity); + $this->assertIdentical($config->isNew(), TRUE); + + // Ensure that schema provided by modules that are not installed is not + // available. + $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')); + + // Verify that default module config exists. + \Drupal::configFactory()->reset($default_config); + \Drupal::configFactory()->reset($default_configuration_entity); + $config = $this->config($default_config); + $this->assertIdentical($config->isNew(), FALSE); + $config = $this->config($default_configuration_entity); + $this->assertIdentical($config->isNew(), FALSE); + + // Verify that config_test API hooks were invoked for the dynamic default + // configuration entity. + $this->assertFalse(isset($GLOBALS['hook_config_test']['load'])); + $this->assertTrue(isset($GLOBALS['hook_config_test']['presave'])); + $this->assertTrue(isset($GLOBALS['hook_config_test']['insert'])); + $this->assertFalse(isset($GLOBALS['hook_config_test']['update'])); + $this->assertFalse(isset($GLOBALS['hook_config_test']['predelete'])); + $this->assertFalse(isset($GLOBALS['hook_config_test']['delete'])); + + // Install the schema test module. + $this->enableModules(array('config_schema_test')); + $this->installConfig(array('config_schema_test')); + + // After module installation the new schema should exist. + $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.someschema'), 'Configuration schema for config_schema_test.someschema does not exist.'); } - catch (PreExistingConfigException $e) { - $this->assertEqual($e->getExtension(), 'config_collection_clash_install_test'); - $this->assertEqual($e->getConfigObjects(), [ - 'another_collection' => ['config_collection_install_test.test'], - 'collection.test1' => ['config_collection_install_test.test'], - 'collection.test2' => ['config_collection_install_test.test'], - ]); - $this->assertEqual($e->getMessage(), 'Configuration objects (another_collection/config_collection_install_test.test, collection/test1/config_collection_install_test.test, collection/test2/config_collection_install_test.test) provided by config_collection_clash_install_test already exist in active configuration'); + + /** + * Tests that collections are ignored if the event does not return anything. + */ + public function testCollectionInstallationNoCollections() { + // Install the test module. + $this->enableModules(array('config_collection_install_test')); + $this->installConfig(array('config_collection_install_test')); + /** @var \Drupal\Core\Config\StorageInterface $active_storage */ + $active_storage = \Drupal::service('config.storage'); + $this->assertEqual(array(), $active_storage->getAllCollectionNames()); + } + + /** + * Tests config objects in collections are installed as expected. + */ + public function testCollectionInstallationCollections() { + $collections = array( + 'another_collection', + 'collection.test1', + 'collection.test2', + ); + // Set the event listener to return three possible collections. + // @see \Drupal\config_collection_install_test\EventSubscriber + \Drupal::state()->set('config_collection_install_test.collection_names', $collections); + // Install the test module. + $this->enableModules(array('config_collection_install_test')); + $this->installConfig(array('config_collection_install_test')); + /** @var \Drupal\Core\Config\StorageInterface $active_storage */ + $active_storage = \Drupal::service('config.storage'); + $this->assertEqual($collections, $active_storage->getAllCollectionNames()); + foreach ($collections as $collection) { + $collection_storage = $active_storage->createCollection($collection); + $data = $collection_storage->read('config_collection_install_test.test'); + $this->assertEqual($collection, $data['collection']); + } + + // Tests that clashing configuration in collections is detected. + try { + \Drupal::service('module_installer')->install(['config_collection_clash_install_test']); + $this->fail('Expected PreExistingConfigException not thrown.'); + } + catch (PreExistingConfigException $e) { + $this->assertEqual($e->getExtension(), 'config_collection_clash_install_test'); + $this->assertEqual($e->getConfigObjects(), [ + 'another_collection' => ['config_collection_install_test.test'], + 'collection.test1' => ['config_collection_install_test.test'], + 'collection.test2' => ['config_collection_install_test.test'], + ]); + $this->assertEqual($e->getMessage(), 'Configuration objects (another_collection/config_collection_install_test.test, collection/test1/config_collection_install_test.test, collection/test2/config_collection_install_test.test) provided by config_collection_clash_install_test already exist in active configuration'); + } + + // Test that the we can use the config installer to install all the + // available default configuration in a particular collection for enabled + // extensions. + \Drupal::service('config.installer')->installCollectionDefaultConfig('entity'); + // The 'entity' collection will not exist because the 'config_test' module + // is not enabled. + $this->assertEqual($collections, $active_storage->getAllCollectionNames()); + // Enable the 'config_test' module and try again. + $this->enableModules(array('config_test')); + \Drupal::service('config.installer')->installCollectionDefaultConfig('entity'); + $collections[] = 'entity'; + $this->assertEqual($collections, $active_storage->getAllCollectionNames()); + $collection_storage = $active_storage->createCollection('entity'); + $data = $collection_storage->read('config_test.dynamic.dotted.default'); + $this->assertIdentical(array('label' => 'entity'), $data); + + // Test that the config manager uninstalls configuration from collections + // as expected. + \Drupal::service('config.manager')->uninstall('module', 'config_collection_install_test'); + $this->assertEqual(array('entity'), $active_storage->getAllCollectionNames()); + \Drupal::service('config.manager')->uninstall('module', 'config_test'); + $this->assertEqual(array(), $active_storage->getAllCollectionNames()); + } + + /** + * Tests collections which do not support config entities install correctly. + * + * Config entity detection during config installation is done by matching + * config name prefixes. If a collection provides a configuration with a + * matching name but does not support config entities it should be created + * using simple configuration. + */ + public function testCollectionInstallationCollectionConfigEntity() { + $collections = array( + 'entity', + ); + \Drupal::state()->set('config_collection_install_test.collection_names', $collections); + // Install the test module. + $this->installModules(array('config_test', 'config_collection_install_test')); + /** @var \Drupal\Core\Config\StorageInterface $active_storage */ + $active_storage = \Drupal::service('config.storage'); + $this->assertEqual($collections, $active_storage->getAllCollectionNames()); + $collection_storage = $active_storage->createCollection('entity'); + + // The config_test.dynamic.dotted.default configuraton object saved in the + // active store should be a configuration entity complete with UUID. Because + // the entity collection does not support configuration entities the + // configuration object stored there with the same name should only contain + // a label. + $name = 'config_test.dynamic.dotted.default'; + $data = $active_storage->read($name); + $this->assertTrue(isset($data['uuid'])); + $data = $collection_storage->read($name); + $this->assertIdentical(array('label' => 'entity'), $data); + } + + /** + * Tests the configuration with unmet dependencies is not installed. + */ + public function testDependencyChecking() { + $this->installModules(['config_test']); + try { + $this->installModules(['config_install_dependency_test']); + $this->fail('Expected UnmetDependenciesException not thrown.'); + } + catch (UnmetDependenciesException $e) { + $this->assertEqual($e->getExtension(), 'config_install_dependency_test'); + $this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency']); + $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.other_module_test_with_dependency) provided by config_install_dependency_test have unmet dependencies'); + } + $this->installModules(['config_other_module_config_test']); + $this->installModules(['config_install_dependency_test']); + $this->assertTrue(entity_load('config_test', 'other_module_test_with_dependency'), 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.'); } - // Test that the we can use the config installer to install all the - // available default configuration in a particular collection for enabled - // extensions. - \Drupal::service('config.installer')->installCollectionDefaultConfig('entity'); - // The 'entity' collection will not exist because the 'config_test' module - // is not enabled. - $this->assertEqual($collections, $active_storage->getAllCollectionNames()); - // Enable the 'config_test' module and try again. - $this->enableModules(array('config_test')); - \Drupal::service('config.installer')->installCollectionDefaultConfig('entity'); - $collections[] = 'entity'; - $this->assertEqual($collections, $active_storage->getAllCollectionNames()); - $collection_storage = $active_storage->createCollection('entity'); - $data = $collection_storage->read('config_test.dynamic.dotted.default'); - $this->assertIdentical(array('label' => 'entity'), $data); - - // Test that the config manager uninstalls configuration from collections - // as expected. - \Drupal::service('config.manager')->uninstall('module', 'config_collection_install_test'); - $this->assertEqual(array('entity'), $active_storage->getAllCollectionNames()); - \Drupal::service('config.manager')->uninstall('module', 'config_test'); - $this->assertEqual(array(), $active_storage->getAllCollectionNames()); - } - - /** - * Tests collections which do not support config entities install correctly. - * - * Config entity detection during config installation is done by matching - * config name prefixes. If a collection provides a configuration with a - * matching name but does not support config entities it should be created - * using simple configuration. - */ - public function testCollectionInstallationCollectionConfigEntity() { - $collections = array( - 'entity', - ); - \Drupal::state()->set('config_collection_install_test.collection_names', $collections); - // Install the test module. - $this->installModules(array('config_test', 'config_collection_install_test')); - /** @var \Drupal\Core\Config\StorageInterface $active_storage */ - $active_storage = \Drupal::service('config.storage'); - $this->assertEqual($collections, $active_storage->getAllCollectionNames()); - $collection_storage = $active_storage->createCollection('entity'); - - // The config_test.dynamic.dotted.default configuraton object saved in the - // active store should be a configuration entity complete with UUID. Because - // the entity collection does not support configuration entities the - // configuration object stored there with the same name should only contain - // a label. - $name = 'config_test.dynamic.dotted.default'; - $data = $active_storage->read($name); - $this->assertTrue(isset($data['uuid'])); - $data = $collection_storage->read($name); - $this->assertIdentical(array('label' => 'entity'), $data); - } - - /** - * Tests the configuration with unmet dependencies is not installed. - */ - public function testDependencyChecking() { - $this->installModules(['config_test']); - try { - $this->installModules(['config_install_dependency_test']); - $this->fail('Expected UnmetDependenciesException not thrown.'); + /** + * Tests imported configuration entities with and without language information. + */ + function testLanguage() { + $this->installModules(['config_test_language']); + // Test imported configuration with implicit language code. + $data = $this->container->get('config.storage.installer')->read('config_test.dynamic.dotted.english'); + $this->assertTrue(!isset($data['langcode'])); + $this->assertEqual( + $this->config('config_test.dynamic.dotted.english')->get('langcode'), + 'en' + ); + + // Test imported configuration with explicit language code. + $data = $this->container->get('config.storage.installer')->read('config_test.dynamic.dotted.french'); + $this->assertEqual($data['langcode'], 'fr'); + $this->assertEqual( + $this->config('config_test.dynamic.dotted.french')->get('langcode'), + 'fr' + ); } - catch (UnmetDependenciesException $e) { - $this->assertEqual($e->getExtension(), 'config_install_dependency_test'); - $this->assertEqual($e->getConfigObjects(), ['config_test.dynamic.other_module_test_with_dependency']); - $this->assertEqual($e->getMessage(), 'Configuration objects (config_test.dynamic.other_module_test_with_dependency) provided by config_install_dependency_test have unmet dependencies'); + + /** + * Installs a module. + * + * @param array $modules + * The module names. + */ + protected function installModules(array $modules) { + $this->container->get('module_installer')->install($modules); + $this->container = \Drupal::getContainer(); } - $this->installModules(['config_other_module_config_test']); - $this->installModules(['config_install_dependency_test']); - $this->assertTrue(entity_load('config_test', 'other_module_test_with_dependency'), 'The config_test.dynamic.other_module_test_with_dependency configuration has been created during install.'); - } - - /** - * Tests imported configuration entities with and without language information. - */ - function testLanguage() { - $this->installModules(['config_test_language']); - // Test imported configuration with implicit language code. - $data = $this->container->get('config.storage.installer')->read('config_test.dynamic.dotted.english'); - $this->assertTrue(!isset($data['langcode'])); - $this->assertEqual( - $this->config('config_test.dynamic.dotted.english')->get('langcode'), - 'en' - ); - - // Test imported configuration with explicit language code. - $data = $this->container->get('config.storage.installer')->read('config_test.dynamic.dotted.french'); - $this->assertEqual($data['langcode'], 'fr'); - $this->assertEqual( - $this->config('config_test.dynamic.dotted.french')->get('langcode'), - 'fr' - ); - } - - /** - * Installs a module. - * - * @param array $modules - * The module names. - */ - protected function installModules(array $modules) { - $this->container->get('module_installer')->install($modules); - $this->container = \Drupal::getContainer(); - } } 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 2ae0ace..0000000 --- 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 6b4f62d..cb870d9 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: mapping - 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 060a2b0..6c27522 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/contact/contact.module b/core/modules/contact/contact.module index 110a6e4..85c5f74 100644 --- a/core/modules/contact/contact.module +++ b/core/modules/contact/contact.module @@ -24,8 +24,10 @@ function contact_help($route_name, RouteMatchInterface $route_match) { $output .= '
' . t('Add one or more forms on this page to set up your site-wide contact form.', array('@form' => \Drupal::url('contact.site_page'))) . '
'; - $output .= '' . t('A Contact menu item is added to the Footer menu, which you can modify on the Menus administration page.', array('@menu-settings' => \Drupal::url('entity.menu.collection'))) . '
'; + if (\Drupal::moduleHandler()->moduleExists('menu_ui')) { + $output .= '' . t('A Contact menu item is added to the Footer menu, which you can modify on the Menus administration page.', array('@menu-settings' => \Drupal::url('entity.menu.collection'))) . '
'; + } $output .= '' . t('If you would like additional text to appear on the site-wide contact page, use a block. You can create and edit blocks on the Blocks administration page.', array('@blocks' => \Drupal::url('block.admin_display'))) . '
'; return $output; } diff --git a/core/modules/forum/config/install/node.type.forum.yml b/core/modules/forum/config/install/node.type.forum.yml index 8ed965d..b03afe0 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 951e4a3..cfbcca5 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/language/src/Config/LanguageConfigOverride.php b/core/modules/language/src/Config/LanguageConfigOverride.php index 5be48ad..b673f34 100644 --- a/core/modules/language/src/Config/LanguageConfigOverride.php +++ b/core/modules/language/src/Config/LanguageConfigOverride.php @@ -50,13 +50,16 @@ public function __construct($name, StorageInterface $storage, TypedConfigManager /** * {@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 b1b4f05..4b3a9ae 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 e882bf3..af0b82c 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/options/src/Plugin/Field/FieldType/ListFloatItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php index 8fd6e29..9ce7cb0 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 @@ public static function simplifyAllowedValues(array $structured_values) { 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 5992386..2ded4ca 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 @@ protected static function validateAllowedValue($option) { } } + /** + * {@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 bdf063a..9b785d8 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 @@ protected static function structureAllowedValues(array $values) { $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 f3bf401..da30810 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 @@ protected static function validateAllowedValue($option) { } } + /** + * {@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 f355b2e..1d02c61 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/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 5a4bda2..2a0e7a9 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -2294,7 +2294,7 @@ public function calculateCacheMetadata () { $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 5aeac87..e01c359 100644 --- a/core/modules/views_ui/src/ViewUI.php +++ b/core/modules/views_ui/src/ViewUI.php @@ -1271,4 +1271,18 @@ public function getThirdPartyProviders() { return $this->storage->getThirdPartyProviders(); } + /** + * {@inheritdoc} + */ + public function trustData() { + return $this->storage->trustData(); + } + + /** + * {@inheritdoc} + */ + public function hasTrustedData() { + return $this->storage->hasTrustedData(); + } + }