diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php new file mode 100644 index 0000000..f341ec1 --- /dev/null +++ b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php @@ -0,0 +1,128 @@ +configName = $config_name; + if (!$typed_config->hasConfigSchema($config_name)) { + return FALSE; + } + $definition = $typed_config->getDefinition($config_name); + $this->schema = $typed_config->create($definition, $config_data); + foreach ($config_data as $key => $value) { + $errors = $this->checkValue($key, $value); + } + if (empty($errors)) { + return TRUE; + } + return $errors; + } + + /** + * Helper method to check data type. + * + * @param string $key + * A string of configuration key. + * @param mixed $value + * Value of given key. + * + * @return array + * List of errors found while checking with the corresponding schema. + */ + protected function checkValue($key, $value) { + $error_key = $this->configName . ':' . $key; + $element = FALSE; + try { + $element = $this->schema->get($key); + } + catch (SchemaIncompleteException $e) { + if (is_scalar($value) || $value === NULL) { + return array($error_key => 'Missing schema.'); + } + } + // Do not check value if it is defined to be ignored. + if ($element && $element instanceof Ignore) { + return array(); + } + + if ($element && is_scalar($value) || $value === NULL) { + $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. + ($value === NULL); + } + $class = get_class($element); + if (!$success) { + return array($error_key => "Variable type is $type but applied schema class is $class."); + } + } + else { + $errors = array(); + if (!$element instanceof ArrayElement) { + $errors[$error_key] = 'Non-scalar value but not defined as an array (such as mapping or sequence)'; + } + + // Go on processing so we can get errors on all levels. Any non-scalar + // value must be an array so cast to an array. + if (!is_array($value)) { + $value = (array) $value; + } + // Recurse into any nested keys. + foreach ($value as $nested_value_key => $nested_value) { + $errors = array_merge($errors, $this->checkValue($key . '.' . $nested_value_key, $nested_value)); + } + return $errors; + } + } +} diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php index eac1a75..f1400d0 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTestBase.php @@ -7,42 +7,16 @@ namespace Drupal\config\Tests; -use Drupal\Core\Config\Schema\ArrayElement; use Drupal\Core\Config\TypedConfigManagerInterface; -use Drupal\Core\TypedData\Type\BooleanInterface; -use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Component\Utility\String; -use Drupal\Core\Config\Schema\SchemaIncompleteException; -use Drupal\Core\TypedData\PrimitiveInterface; -use Drupal\Core\TypedData\Type\FloatInterface; -use Drupal\Core\TypedData\Type\IntegerInterface; +use Drupal\Core\Config\Schema\SchemaCheckTrait; use Drupal\simpletest\WebTestBase; /** * Provides a base class to help test configuration schema. */ abstract class ConfigSchemaTestBase extends WebTestBase { - - /** - * The config schema wrapper object for the configuration object under test. - * - * @var \Drupal\Core\Config\Schema\Element - */ - protected $schema; - - /** - * The configuration object name under test. - * - * @var string - */ - protected $configName; - - /** - * Global state for whether the config has a valid schema. - * - * @var boolean - */ - protected $configPass; + use SchemaCheckTrait; /** * Asserts the TypedConfigManager has a valid schema for the configuration. @@ -55,89 +29,18 @@ * The configuration data. */ public function assertConfigSchema(TypedConfigManagerInterface $typed_config, $config_name, $config_data) { - $this->configName = $config_name; - if (!$typed_config->hasConfigSchema($config_name)) { + $errors = $this->checkConfigSchema($typed_config, $config_name, $config_data); + if ($errors === FALSE) { $this->fail(String::format('No schema for !config_name', array('!config_name' => $config_name))); return; } - $definition = $typed_config->getDefinition($config_name); - $this->schema = $typed_config->create($definition, $config_data); - $this->configPass = TRUE; - foreach ($config_data as $key => $value) { - $this->checkValue($key, $value); - } - if ($this->configPass) { + elseif ($errors === TRUE) { $this->pass(String::format('Schema found for !config_name and values comply with schema.', array('!config_name' => $config_name))); } - } - - /** - * Helper method to check data type. - * - * @param string $key - * A string of configuration key. - * @param mixed $value - * Value of given key. - * - * @return mixed - * 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) { - $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. - ($value === NULL); - } - $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 { - if (!$element instanceof ArrayElement) { - $this->fail("Non-scalar {$this->configName}:$key is not defined as an array type (such as mapping or sequence)."); - } - - // Go on processing so we can get errors on all levels. Any non-scalar - // value must be an array so cast to an array. - if (!is_array($value)) { - $value = (array) $value; - } - // Recurse into any nested keys. - foreach ($value as $nested_value_key => $nested_value) { - $value[$nested_value_key] = $this->checkValue($key . '.' . $nested_value_key, $nested_value); + foreach ($errors as $key => $error) { + $this->fail($key . ': ' . $error); } } - return $value; - } - - /** - * {@inheritdoc} - */ - protected function fail($message = NULL, $group = 'Other') { - $this->configPass = FALSE; - return parent::fail($message, $group); } - }