diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index 8e14b36..d75df89 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -18,21 +18,20 @@ uri: label: 'Uri' class: '\Drupal\Core\TypedData\Plugin\DataType\Uri' -# Basic data types for configuration. +# Undefined type to use for missing schema, don't use explicitly. undefined: label: 'Undefined' - class: '\Drupal\Core\Config\Schema\Property' + class: '\Drupal\Core\Config\Schema\Undefined' + +# Explicit type when no data typing is possible. Avoid if at all possible. +ignore: + label: 'Ignore' + class: '\Drupal\Core\Config\Schema\Ignore' + +# Container data types with lists with known and uknown keys. mapping: label: Mapping class: '\Drupal\Core\Config\Schema\Mapping' -sequence: - label: Sequence - class: '\Drupal\Core\Config\Schema\Sequence' - -# Default mapping for unknown types or types not found. -default: - type: undefined - label: 'Unknown' # Simple extended data types: diff --git a/core/lib/Drupal/Core/Config/Schema/Ignore.php b/core/lib/Drupal/Core/Config/Schema/Ignore.php new file mode 100644 index 0000000..a616306 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Schema/Ignore.php @@ -0,0 +1,14 @@ +value); - } - -} diff --git a/core/lib/Drupal/Core/Config/Schema/Undefined.php b/core/lib/Drupal/Core/Config/Schema/Undefined.php new file mode 100644 index 0000000..6e98a1a --- /dev/null +++ b/core/lib/Drupal/Core/Config/Schema/Undefined.php @@ -0,0 +1,14 @@ +getSchemaWrapper()->get($key); } - elseif (is_scalar($value)) { - try { - $element = $this->getSchemaWrapper()->get($key); - if ($element instanceof PrimitiveInterface) { - // Special handling for integers and floats since the configuration - // system is primarily concerned with saving values from the Form API - // we have to special case the meaning of an empty string for numeric - // types. In PHP this would be casted to a 0 but for the purposes of - // configuration we need to treat this as a NULL. - if ($value === '' && ($element instanceof IntegerInterface || $element instanceof FloatInterface)) { - $value = NULL; - } - else { - $value = $element->getCastedValue(); - } + catch (SchemaIncompleteException $e) { + // @todo throw an exception due to an incomplete schema. + // Fix as part of https://drupal.org/node/2183983. + } + // Do not cast value if it is unknown or defined to be ignored. + if ($element && ($element instanceof Undefined || $element instanceof Ignore)) { + return $value; + } + if ((is_scalar($value) || $value === NULL)) { + if ($element && $element instanceof PrimitiveInterface) { + // Special handling for integers and floats since the configuration + // system is primarily concerned with saving values from the Form API + // we have to special case the meaning of an empty string for numeric + // types. In PHP this would be casted to a 0 but for the purposes of + // configuration we need to treat this as a NULL. + $empty_value = $value === '' && ($element instanceof IntegerInterface || $element instanceof FloatInterface); + + if ($value === NULL || $empty_value) { + $value = NULL; } else { - // Config only supports primitive data types. If the config schema - // does define a type $element will be an instance of - // \Drupal\Core\Config\Schema\Property. Convert it to string since it - // is the safest possible type. - $value = $element->getString(); + $value = $element->getCastedValue(); } } - catch (SchemaIncompleteException $e) { - // @todo throw an exception due to an incomplete schema. - // Fix as part of https://drupal.org/node/2183983. - } } else { // Throw exception on any non-scalar or non-array value. diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php index 647d00f..f587c6e 100644 --- a/core/lib/Drupal/Core/Config/TypedConfigManager.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php @@ -326,10 +326,9 @@ protected function replaceVariable($value, $data) { * {@inheritdoc} */ public function hasConfigSchema($name) { - // The schema system falls back on the Property class for unknown types. - // See http://drupal.org/node/1905230 + // The schema system falls back on the Undefined class for unknown types. $definition = $this->getDefinition($name); - return is_array($definition) && ($definition['class'] != '\Drupal\Core\Config\Schema\Property'); + return is_array($definition) && ($definition['class'] != '\Drupal\Core\Config\Schema\Undefined'); } } diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php index 173955f..8b129bc 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php @@ -45,7 +45,7 @@ function testSchemaMapping() { $definition = \Drupal::service('config.typed')->getDefinition('config_schema_test.no_such_key'); $expected = array(); $expected['label'] = 'Unknown'; - $expected['class'] = '\Drupal\Core\Config\Schema\Property'; + $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.'); // Configuration file without schema will return Unknown as well. @@ -68,13 +68,13 @@ function testSchemaMapping() { $definition = $config['testitem']->getDataDefinition(); $expected = array(); $expected['label'] = 'Test item'; - $expected['class'] = '\Drupal\Core\Config\Schema\Property'; + $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $expected['type'] = 'undefined'; $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.'); $definition = $config['testlist']->getDataDefinition(); $expected = array(); $expected['label'] = 'Test list'; - $expected['class'] = '\Drupal\Core\Config\Schema\Property'; + $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $expected['type'] = 'undefined'; $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.'); @@ -254,7 +254,7 @@ public function testConfigSaveWithSchema() { 'integer' => '100', 'null_integer' => '', 'boolean' => 1, - // If the config schema doesn't have a type it should be casted to string. + // If the config schema doesn't have a type it shouldn't be casted. 'no_type' => 1, 'mapping' => array( 'string' => 1 @@ -277,7 +277,7 @@ public function testConfigSaveWithSchema() { 'integer' => 100, 'null_integer' => NULL, 'boolean' => TRUE, - 'no_type' => '1', + 'no_type' => 1, 'mapping' => array( 'string' => '1' ), diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php index 61eee7e..02e7027 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php @@ -7,7 +7,6 @@ namespace Drupal\config\Tests; -use Drupal\Core\Config\Schema\Property; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\TypedData\Type\BooleanInterface; use Drupal\Core\TypedData\Type\StringInterface; @@ -92,40 +91,35 @@ public function assertConfigSchema(TypedConfigManagerInterface $typed_config, $c * Returns mixed value. */ protected function checkValue($key, $value) { + $element = FALSE; + try { + $element = $this->schema->get($key); + } + catch (SchemaIncompleteException $e) { + if (is_scalar($value) || $value === NULL) { + $this->fail("{$this->configName}:$key has no schema."); + } + } + // Do not check value if it is defined to be ignored. + if ($element && $element instanceof Ignore) { + return $value; + } + if (is_scalar($value) || $value === NULL) { - try { - $success = FALSE; - $type = gettype($value); - $element = $this->schema->get($key); - if ($element instanceof PrimitiveInterface) { - if ($type == 'integer' && $element instanceof IntegerInterface) { - $success = TRUE; - } - if ($type == 'double' && $element instanceof FloatInterface) { - $success = TRUE; - } - if ($type == 'boolean' && $element instanceof BooleanInterface) { - $success = TRUE; - } - if ($type == 'string' && ($element instanceof StringInterface || $element instanceof Property)) { - $success = TRUE; - } + $success = FALSE; + $type = gettype($value); + if ($element instanceof PrimitiveInterface) { + $success = + ($type == 'integer' && $element instanceof IntegerInterface) || + ($type == 'double' && $element instanceof FloatInterface) || + ($type == 'boolean' && $element instanceof BooleanInterface) || + ($type == 'string' && $element instanceof StringInterface) || // Null values are allowed for all types. - if ($value === NULL) { - $success = TRUE; - } - } - else { - // @todo throw an exception due to an incomplete schema. Only possible - // once https://drupal.org/node/1910624 is complete. - } - $class = get_class($element); - if (!$success) { - $this->fail("{$this->configName}:$key has the wrong schema. Variable type is $type and schema class is $class."); - } + ($value === NULL); } - catch (SchemaIncompleteException $e) { - $this->fail("{$this->configName}:$key has no schema."); + $class = get_class($element); + if (!$success) { + $this->fail("{$this->configName}:$key has the wrong schema. Variable type is $type and schema class is $class."); } } else {