diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index 2b86cd7..ba18dc7 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -42,9 +42,11 @@ uri: mapping: label: Mapping class: '\Drupal\Core\Config\Schema\Mapping' + definition_class: '\Drupal\Core\TypedData\MapDataDefinition' sequence: label: Sequence class: '\Drupal\Core\Config\Schema\Sequence' + definition_class: '\Drupal\Core\TypedData\ListDataDefinition' # Simple extended data types: @@ -110,7 +112,6 @@ filter: settings: type: filter_settings.[%parent.id] - # System action configuration base. action_configuration_default: type: sequence diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php index 2563ec5..c492d42 100644 --- a/core/lib/Drupal/Core/Config/Schema/Element.php +++ b/core/lib/Drupal/Core/Config/Schema/Element.php @@ -28,4 +28,13 @@ protected function parseElement($key, $data, $definition) { return \Drupal::service('config.typed')->create($definition, $data, $key, $this); } + /** + * Build data definition object for contained elements. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface + */ + protected function buildDataDefinition($definition, $value, $key) { + return \Drupal::service('config.typed')->buildDataDefinition($definition, $value, $key, $this); + } + } diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php index 19fb596..82fffe7 100644 --- a/core/lib/Drupal/Core/Config/Schema/Mapping.php +++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php @@ -20,14 +20,19 @@ class Mapping extends ArrayElement implements ComplexDataInterface { /** + * An array of data definitions. + * + * @var \Drupal\Core\TypedData\DataDefinitionInterface[] + */ + protected $propertyDefinitions; + + /** * Overrides ArrayElement::parse() */ protected function parse() { $elements = array(); - foreach ($this->definition['mapping'] as $key => $definition) { - if (isset($this->value[$key]) || array_key_exists($key, $this->value)) { - $elements[$key] = $this->parseElement($key, $this->value[$key], $definition); - } + foreach ($this->getPropertyDefinitions() as $key => $definition) { + $elements[$key] = $this->parseElement($key, $this->value[$key], $definition); } return $elements; } @@ -44,19 +49,22 @@ public function get($property_name) { $elements = $this->getElements(); if (isset($elements[$root_key])) { $element = $elements[$root_key]; + // If $property_name contained a dot recurse into the keys. + while ($element && $key = array_shift($parts)) { + if (method_exists($element, 'get')) { + $element = $element->get($key); + } + else { + $element = NULL; + } + } } - else { - throw new SchemaIncompleteException(String::format("The configuration property @key doesn't exist.", array('@key' => $property_name))); + if (isset($element)) { + return $element; } - - // If $property_name contained a dot recurse into the keys. - foreach ($parts as $key) { - if (!is_object($element) || !method_exists($element, 'get')) { - throw new SchemaIncompleteException(String::format("The configuration property @key does not exist.", array('@key' => $property_name))); - } - $element = $element->get($key); + else { + throw new \InvalidArgumentException(String::format("The configuration property @key doesn't exist.", array('@key' => $property_name))); } - return $element; } /** @@ -103,28 +111,34 @@ public function toArray() { * @param string $name * The name of property. * - * @return array|null - * The definition of the property or NULL if the property does not exist. + * @return \Drupal\Core\TypedData\DataDefinitionInterface + * The definition of the property that will be of type 'undefined' if we + * don't have a mapping for it. */ - public function getPropertyDefinition($name) { - if (isset($this->definition['mapping'][$name])) { - return $this->definition['mapping'][$name]; - } + protected function getPropertyDefinition($name) { + $definition = isset($this->definition['mapping'][$name]) ? $this->definition['mapping'][$name] : array(); + $value = isset($this->value[$name]) ? $this->value[$name] : NULL; + return $this->buildDataDefinition($definition, $value, $name); } /** * Gets an array of property definitions of contained properties. * + * For each data property not existing in the mapping we also return a + * a definition of type 'undefined'. + * * @return \Drupal\Core\TypedData\DataDefinitionInterface[] * An array of property definitions of contained properties, keyed by * property name. */ - public function getPropertyDefinitions() { - $list = array(); - foreach ($this->getAllKeys() as $key) { - $list[$key] = $this->getPropertyDefinition($key); + protected function getPropertyDefinitions() { + if (!isset($this->propertyDefinitions)) { + $this->propertyDefinitions = array(); + foreach ($this->getAllKeys() as $key) { + $this->propertyDefinitions[$key] = $this->getPropertyDefinition($key); + } } - return $list; + return $this->propertyDefinitions; } /** diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php index 720b850..e5b6a35 100644 --- a/core/lib/Drupal/Core/Config/Schema/Sequence.php +++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php @@ -15,13 +15,25 @@ class Sequence extends ArrayElement implements ListInterface { /** + * Data definition + * + * @var \Drupal\Core\TypedData\DataDefinitionInterface + */ + protected $itemDefinition; + + /** * Overrides ArrayElement::parse() */ protected function parse() { - $definition = $this->getItemDefinition(); + // Creates a new data definition object for each item from the generic type + // definition array and actual configuration data for that item. Type + // definitions may contain variables to be replaced and those depend on + // each item's data. + $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array(); $elements = array(); foreach ($this->value as $key => $value) { - $elements[$key] = $this->parseElement($key, $value, $definition); + $data_definition = $this->buildDataDefinition($definition, $value, $key); + $elements[$key] = $this->parseElement($key, $value, $data_definition); } return $elements; } @@ -37,7 +49,11 @@ public function isEmpty() { * Implements Drupal\Core\TypedData\ListInterface::getItemDefinition(). */ public function getItemDefinition() { - return $this->definition['sequence'][0]; + if (!isset($this->itemDefinition)) { + $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array(); + $this->itemDefinition = $this->buildDataDefinition($definition, NULL); + } + return $this->itemDefinition; } /** diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php index 60a1d02..b2610f7 100644 --- a/core/lib/Drupal/Core/Config/StorableConfigBase.php +++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php @@ -128,7 +128,8 @@ public function getStorage() { protected function getSchemaWrapper() { if (!isset($this->schemaWrapper)) { $definition = $this->typedConfigManager->getDefinition($this->name); - $this->schemaWrapper = $this->typedConfigManager->create($definition, $this->data); + $data_definition = $this->typedConfigManager->buildDataDefinition($definition, $this->data); + $this->schemaWrapper = $this->typedConfigManager->create($data_definition, $this->data); } return $this->schemaWrapper; } diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php index 2032f4c..938593c 100644 --- a/core/lib/Drupal/Core/Config/TypedConfigManager.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php @@ -12,11 +12,17 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\String; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\TypedData\DataDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\ListDataDefinition; +use Drupal\Core\TypedData\ListDataDefinitionInterface; +use Drupal\Core\TypedData\MapDataDefinition; +use Drupal\Core\TypedData\TypedDataManager; /** * Manages config type plugins. */ -class TypedConfigManager extends PluginManagerBase implements TypedConfigManagerInterface { +class TypedConfigManager extends TypedDataManager implements TypedConfigManagerInterface { /** * The cache ID for the definitions. @@ -80,19 +86,19 @@ public function __construct(StorageInterface $configStorage, StorageInterface $s */ public function get($name) { $data = $this->configStorage->read($name); - $definition = $this->getDefinition($name); - return $this->create($definition, $data); + $type_definition = $this->getDefinition($name); + $data_definition = $this->buildDataDefinition($type_definition, $data); + return $this->create($data_definition, $data); } /** * {@inheritdoc} */ - public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL) { - if (!isset($definition['type'])) { - // By default elements without a type are undefined. - $definition['type'] = 'undefined'; - } - elseif (strpos($definition['type'], ']')) { + public function buildDataDefinition(array $definition, $value, $name = NULL, $parent = NULL) { + // Add default values for data type and replace variables. + $definition += array('type' => 'undefined'); + + if (strpos($definition['type'], ']')) { // Replace variable names in definition. $replace = is_array($value) ? $value : array(); if (isset($parent)) { @@ -103,45 +109,18 @@ public function create(array $definition, $value = NULL, $name = NULL, $parent = } $definition['type'] = $this->replaceName($definition['type'], $replace); } - // Create typed config object. - $wrapper = $this->createInstance($definition['type'], array( - 'data_definition' => $definition, - 'name' => $name, - 'parent' => $parent, - )); - if (isset($value)) { - $wrapper->setValue($value, FALSE); - } - return $wrapper; - } + // Add default values from type definition. + $definition += $this->getDefinition($definition['type']); - /** - * {@inheritdoc} - */ - public function createInstance($data_type, array $configuration = array()) { - $data_definition = $configuration['data_definition']; - $type_definition = $this->getDefinition($data_type); + $data_definition = $this->createDataDefinition($definition['type']); - if (!isset($type_definition)) { - throw new \InvalidArgumentException(String::format('Invalid data type %plugin_id has been given.', array('%plugin_id' => $data_type))); - } - - // Allow per-data definition overrides of the used classes, i.e. take over - // classes specified in the type definition. - $data_definition += $type_definition; - - $key = empty($data_definition['list']) ? 'class' : 'list class'; - if (isset($data_definition[$key])) { - $class = $data_definition[$key]; - } - elseif (isset($type_definition[$key])) { - $class = $type_definition[$key]; - } - - if (!isset($class)) { - throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $data_type)); + // Pass remaining values from definition array to data definition. + foreach ($definition as $key => $value) { + if (!isset($data_definition[$key])) { + $data_definition[$key] = $value; + } } - return new $class($data_definition, $configuration['name'], $configuration['parent']); + return $data_definition; } /** @@ -169,7 +148,11 @@ public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) { unset($definition['type']); $this->definitions[$type] = $definition; } - return $definition; + // Add type and default definition class. + return $definition + array( + 'definition_class' => '\Drupal\Core\TypedData\DataDefinition', + 'type' => $type, + ); } /** diff --git a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php index 827363f..f475c02 100644 --- a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php +++ b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php @@ -9,6 +9,7 @@ use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface; use Drupal\Component\Plugin\PluginManagerInterface; +use Drupal\Core\TypedData\DataDefinitionInterface; /** * Defines an interface for typed configuration manager. @@ -36,7 +37,8 @@ public function get($name); * instantiated. * @param array $configuration * The plugin configuration array, i.e. an array with the following keys: - * - data definition: The data definition array. + * - data definition: The data definition object, i.e. an instance of + * \Drupal\Core\TypedData\DataDefinitionInterface. * - name: (optional) If a property or list item is to be created, the name * of the property or the delta of the list item. * - parent: (optional) If a property or list item is to be created, the @@ -51,10 +53,10 @@ public function createInstance($data_type, array $configuration = array()); /** * Creates a new typed configuration object instance. * - * @param array $definition - * The data definition of the typed data object + * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition + * The data definition of the typed data object. * @param mixed $value - * (optional) The data value. If set, it has to match one of the supported + * The data value. If set, it has to match one of the supported * data type format as documented for the data type classes. * @param string $name * (optional) If a property or list item is to be created, the name of the @@ -67,7 +69,27 @@ public function createInstance($data_type, array $configuration = array()); * @return \Drupal\Core\Config\Schema\Element * The instantiated typed data object. */ - public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL); + public function create(DataDefinitionInterface $definition, $value, $name = NULL, $parent = NULL); + + /** + * Creates a new data definition object from a type definition array and + * actual configuration data. Since type definitions may contain variables + * to be replaced, we need the configuration value to create it. + * + * @param array $definition + * The base type definition array, for which a data definition should be + * created. + * @param $value + * Optional value of the configuraiton element. + * @param string $name + * Optional name of the configuration element. + * @param object $parent + * Optional parent element. + * + * @return \Drupal\Core\TypedData\DataDefinitionInterface + * A data definition for the given data type. + */ + public function buildDataDefinition(array $definition, $value, $name = NULL, $parent = NULL); /** * Checks if the configuration schema with the given config name exists. diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php index 14161bb..cef3d0d 100644 --- a/core/modules/config/src/Tests/ConfigSchemaTest.php +++ b/core/modules/config/src/Tests/ConfigSchemaTest.php @@ -48,6 +48,8 @@ function testSchemaMapping() { $expected = array(); $expected['label'] = 'Undefined'; $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; + $expected['type'] = 'undefined'; + $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition'; $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.'); // Configuration file without schema will return Undefined as well. @@ -63,21 +65,25 @@ function testSchemaMapping() { $expected['class'] = '\Drupal\Core\Config\Schema\Mapping'; $expected['mapping']['testitem'] = array('label' => 'Test item'); $expected['mapping']['testlist'] = array('label' => 'Test list'); + $expected['type'] = 'config_schema_test.someschema'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with only some schema.'); // Check type detection on elements with undefined types. $config = \Drupal::service('config.typed')->get('config_schema_test.someschema'); - $definition = $config['testitem']->getDataDefinition(); + $definition = $config['testitem']->getDataDefinition()->toArray(); $expected = array(); $expected['label'] = 'Test item'; $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $expected['type'] = 'undefined'; + $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition'; $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.'); - $definition = $config['testlist']->getDataDefinition(); + $definition = $config['testlist']->getDataDefinition()->toArray(); $expected = array(); $expected['label'] = 'Test list'; $expected['class'] = '\Drupal\Core\Config\Schema\Undefined'; $expected['type'] = 'undefined'; + $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition'; $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.'); // Simple case, straight metadata. @@ -93,6 +99,8 @@ function testSchemaMapping() { 'label' => 'Default language', 'type' => 'string', ); + $expected['type'] = 'system.maintenance'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance'); // Mixed schema with ignore elements. @@ -100,6 +108,7 @@ function testSchemaMapping() { $expected = array(); $expected['label'] = 'Ignore test'; $expected['class'] = '\Drupal\Core\Config\Schema\Mapping'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['mapping']['label'] = array( 'label' => 'Label', 'type' => 'label', @@ -116,16 +125,19 @@ function testSchemaMapping() { 'label' => 'Weight', 'type' => 'integer', ); + $expected['type'] = 'config_schema_test.ignore'; + $this->assertEqual($definition, $expected); // The ignore elements themselves. - $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition(); + $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition()->toArray(); $expected = array(); $expected['type'] = 'ignore'; $expected['label'] = 'Irrelevant'; $expected['class'] = '\Drupal\Core\Config\Schema\Ignore'; + $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition'; $this->assertEqual($definition, $expected); - $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition(); + $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition()->toArray(); $expected['label'] = 'Indescribable'; $this->assertEqual($definition, $expected); @@ -134,6 +146,7 @@ function testSchemaMapping() { $expected = array(); $expected['label'] = 'Image style'; $expected['class'] = '\Drupal\Core\Config\Schema\Mapping'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['mapping']['name']['type'] = 'string'; $expected['mapping']['id']['label'] = 'ID'; $expected['mapping']['id']['type'] = 'string'; @@ -154,6 +167,7 @@ function testSchemaMapping() { $expected['mapping']['effects']['sequence'][0]['mapping']['data']['type'] = 'image.effect.[%parent.id]'; $expected['mapping']['effects']['sequence'][0]['mapping']['weight']['type'] = 'integer'; $expected['mapping']['effects']['sequence'][0]['mapping']['uuid']['type'] = 'string'; + $expected['type'] = 'image.style.*'; $this->assertEqual($definition, $expected); @@ -163,18 +177,21 @@ function testSchemaMapping() { $expected = array(); $expected['label'] = 'Image scale'; $expected['class'] = '\Drupal\Core\Config\Schema\Mapping'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['mapping']['width']['type'] = 'integer'; $expected['mapping']['width']['label'] = 'Width'; $expected['mapping']['height']['type'] = 'integer'; $expected['mapping']['height']['label'] = 'Height'; $expected['mapping']['upscale']['type'] = 'boolean'; $expected['mapping']['upscale']['label'] = 'Upscale'; + $expected['type'] = 'image.effect.image_scale'; + $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.effect.image_scale'); // Most complex case, get metadata for actual configuration element. $effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects'); - $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDataDefinition(); + $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDataDefinition()->toArray(); // This should be the schema for image.effect.image_scale, reuse previous one. $expected['type'] = 'image.effect.image_scale'; @@ -190,6 +207,8 @@ function testSchemaMapping() { $expected['mapping']['testid']['label'] = 'ID'; $expected['mapping']['testdescription']['type'] = 'text'; $expected['mapping']['testdescription']['label'] = 'Description'; + $expected['type'] = 'config_schema_test.someschema.somemodule.*.*'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection'); @@ -206,31 +225,34 @@ function testSchemaMappingWithParents() { // Test fetching parent one level up. $entry = $config_data->get('one_level'); - $definition = $entry['testitem']->getDataDefinition(); + $definition = $entry['testitem']->getDataDefinition()->toArray(); $expected = array( 'type' => 'config_schema_test.someschema.with_parents.key_1', 'label' => 'Test item nested one level', 'class' => '\Drupal\Core\TypedData\Plugin\DataType\String', + 'definition_class' => '\Drupal\Core\TypedData\DataDefinition', ); $this->assertEqual($definition, $expected); // Test fetching parent two levels up. $entry = $config_data->get('two_levels'); - $definition = $entry['wrapper']['testitem']->getDataDefinition(); + $definition = $entry['wrapper']['testitem']->getDataDefinition()->toArray(); $expected = array( 'type' => 'config_schema_test.someschema.with_parents.key_2', 'label' => 'Test item nested two levels', 'class' => '\Drupal\Core\TypedData\Plugin\DataType\String', + 'definition_class' => '\Drupal\Core\TypedData\DataDefinition', ); $this->assertEqual($definition, $expected); // Test fetching parent three levels up. $entry = $config_data->get('three_levels'); - $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDataDefinition(); + $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDataDefinition()->toArray(); $expected = array( 'type' => 'config_schema_test.someschema.with_parents.key_3', 'label' => 'Test item nested three levels', 'class' => '\Drupal\Core\TypedData\Plugin\DataType\String', + 'definition_class' => '\Drupal\Core\TypedData\DataDefinition', ); $this->assertEqual($definition, $expected); } @@ -361,10 +383,12 @@ function testSchemaFallback() { $expected = array(); $expected['label'] = 'Schema wildcard fallback test'; $expected['class'] = '\Drupal\Core\Config\Schema\Mapping'; + $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition'; $expected['mapping']['testid']['type'] = 'string'; $expected['mapping']['testid']['label'] = 'ID'; $expected['mapping']['testdescription']['type'] = 'text'; $expected['mapping']['testdescription']['label'] = 'Description'; + $expected['type'] = 'config_schema_test.wildcard_fallback.*'; $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.wildcard_fallback.something'); diff --git a/core/modules/config/src/Tests/ConfigSchemaTestBase.php b/core/modules/config/src/Tests/ConfigSchemaTestBase.php index eac1a75..6c763d4 100644 --- a/core/modules/config/src/Tests/ConfigSchemaTestBase.php +++ b/core/modules/config/src/Tests/ConfigSchemaTestBase.php @@ -61,7 +61,8 @@ public function assertConfigSchema(TypedConfigManagerInterface $typed_config, $c return; } $definition = $typed_config->getDefinition($config_name); - $this->schema = $typed_config->create($definition, $config_data); + $data_definition = $typed_config->buildDataDefinition($definition, $config_data); + $this->schema = $typed_config->create($data_definition, $config_data); $this->configPass = TRUE; foreach ($config_data as $key => $value) { $this->checkValue($key, $value); diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php index 04e1507..1e4273c 100644 --- a/core/modules/config_translation/src/ConfigMapperManager.php +++ b/core/modules/config_translation/src/ConfigMapperManager.php @@ -129,6 +129,13 @@ public function processDefinition(&$definition, $plugin_id) { /** * {@inheritdoc} */ + public function buildDataDefinition(array $definition, $value = NULL, $name = NULL, $parent = NULL) { + return $this->typedConfigManager->buildDataDefinition($definition, $value, $name, $parent); + } + + /** + * {@inheritdoc} + */ protected function findDefinitions() { $definitions = $this->discovery->getDefinitions(); foreach ($definitions as $plugin_id => &$definition) { diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php index a57b60b..5b6125a 100644 --- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php +++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php @@ -272,7 +272,10 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d foreach ($schema as $key => $element) { // Make the specific element key, "$base_key.$key". $element_key = implode('.', array_filter(array($base_key, $key))); - $definition = $element->getDataDefinition() + array('label' => $this->t('N/A')); + $definition = $element->getDataDefinition(); + if (!$definition->getLabel()) { + $definition->setLabel($this->t('N/A')); + } if ($element instanceof Element) { // Build sub-structure and include it with a wrapper in the form // if there are any translatable elements there. @@ -336,7 +339,9 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d '#type' => 'item', ); - $definition += array('form_element_class' => '\Drupal\config_translation\FormElement\Textfield'); + if (!isset($definition['form_element_class'])) { + $definition['form_element_class'] = '\Drupal\config_translation\FormElement\Textfield'; + } /** @var \Drupal\config_translation\FormElement\ElementInterface $form_element */ $form_element = new $definition['form_element_class'](); diff --git a/core/modules/config_translation/src/FormElement/DateFormat.php b/core/modules/config_translation/src/FormElement/DateFormat.php index d82d427..25858cf 100644 --- a/core/modules/config_translation/src/FormElement/DateFormat.php +++ b/core/modules/config_translation/src/FormElement/DateFormat.php @@ -12,6 +12,7 @@ use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\TypedData\DataDefinitionInterface; /** * Defines the date format element for the configuration translation interface. @@ -22,7 +23,7 @@ class DateFormat implements ElementInterface { /** * {@inheritdoc} */ - public function getFormElement(array $definition, LanguageInterface $language, $value) { + public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value) { $description = $this->t('A user-defined date format. See the PHP manual for available options.', array('@url' => 'http://php.net/manual/function.date.php')); $format = $this->t('Displayed as %date_format', array('%date_format' => \Drupal::service('date')->format(REQUEST_TIME, 'custom', $value))); return array( diff --git a/core/modules/config_translation/src/FormElement/ElementInterface.php b/core/modules/config_translation/src/FormElement/ElementInterface.php index ecc93f0..d80048e 100644 --- a/core/modules/config_translation/src/FormElement/ElementInterface.php +++ b/core/modules/config_translation/src/FormElement/ElementInterface.php @@ -8,6 +8,8 @@ namespace Drupal\config_translation\FormElement; use Drupal\Core\Language\LanguageInterface; +use Drupal\Core\Language\Language; +use Drupal\Core\TypedData\DataDefinitionInterface; /** * Provides an interface for configuration translation form elements. @@ -17,7 +19,7 @@ /** * Returns the translation form element for a given configuration definition. * - * @param array $definition + * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition * Configuration schema type definition of the element. * @param \Drupal\Core\Language\LanguageInterface $language * Language object to display the translation form for. @@ -27,6 +29,7 @@ * @return array * Form API array to represent the form element. */ - public function getFormElement(array $definition, LanguageInterface $language, $value); + public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value); + } diff --git a/core/modules/config_translation/src/FormElement/Textarea.php b/core/modules/config_translation/src/FormElement/Textarea.php index 63aecf3..8092e4b 100644 --- a/core/modules/config_translation/src/FormElement/Textarea.php +++ b/core/modules/config_translation/src/FormElement/Textarea.php @@ -9,6 +9,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\TypedData\DataDefinitionInterface; /** * Defines the textarea element for the configuration translation interface. @@ -19,7 +20,7 @@ class Textarea implements ElementInterface { /** * {@inheritdoc} */ - public function getFormElement(array $definition, LanguageInterface $language, $value) { + public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value) { // Estimate a comfortable size of the input textarea. $rows_words = ceil(str_word_count($value) / 5); $rows_newlines = substr_count($value, "\n" ) + 1; diff --git a/core/modules/config_translation/src/FormElement/Textfield.php b/core/modules/config_translation/src/FormElement/Textfield.php index 44105ba..a4a820f 100644 --- a/core/modules/config_translation/src/FormElement/Textfield.php +++ b/core/modules/config_translation/src/FormElement/Textfield.php @@ -9,6 +9,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\TypedData\DataDefinitionInterface; /** * Defines the textfield element for the configuration translation interface. @@ -19,7 +20,7 @@ class Textfield implements ElementInterface { /** * {@inheritdoc} */ - public function getFormElement(array $definition, LanguageInterface $language, $value) { + public function getFormElement(DataDefinitionInterface $definition, LanguageInterface $language, $value) { return array( '#type' => 'textfield', '#default_value' => $value, diff --git a/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php index 4e29ecf..69be476 100644 --- a/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php +++ b/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php @@ -12,6 +12,8 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\TypedData\TypedDataInterface; use Drupal\Tests\UnitTestCase; +use Drupal\Core\TypedData\DataDefinition; +use Drupal\Core\TypedData\DataDefinitionInterface; /** * Tests ConfigMapperManager. @@ -162,10 +164,11 @@ public function providerTestHasTranslatable() { * The mocked schema element. */ protected function getElement(array $definition) { + $data_definition = new DataDefinition($definition); $element = $this->getMock('Drupal\Core\TypedData\TypedDataInterface'); $element->expects($this->any()) ->method('getDataDefinition') - ->will($this->returnValue($definition)); + ->will($this->returnValue($data_definition)); return $element; } diff --git a/core/modules/locale/src/LocaleConfigManager.php b/core/modules/locale/src/LocaleConfigManager.php index 9e0f3de..5466558 100644 --- a/core/modules/locale/src/LocaleConfigManager.php +++ b/core/modules/locale/src/LocaleConfigManager.php @@ -96,9 +96,10 @@ public function get($name) { // We get only the data that didn't change from default. $data = $this->compareConfigData($default, $updated); $definition = $this->getDefinition($name); + $data_definition = $this->buildDataDefinition($definition, $data); // Unless the configuration has a explicit language code we assume English. $langcode = isset($default['langcode']) ? $default['langcode'] : 'en'; - $wrapper = new LocaleTypedConfig($definition, $name, $langcode, $this); + $wrapper = new LocaleTypedConfig($data_definition, $name, $langcode, $this); $wrapper->setValue($data); return $wrapper; } diff --git a/core/modules/locale/src/LocaleTypedConfig.php b/core/modules/locale/src/LocaleTypedConfig.php index dd24d99..36e39a9 100644 --- a/core/modules/locale/src/LocaleTypedConfig.php +++ b/core/modules/locale/src/LocaleTypedConfig.php @@ -8,6 +8,7 @@ namespace Drupal\locale; use Drupal\Core\TypedData\ContextAwareInterface; +use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\Core\Config\Schema\Element; use Drupal\Core\Config\Schema\ArrayElement; @@ -49,7 +50,7 @@ class LocaleTypedConfig extends Element { * @param \Drupal\locale\LocaleConfigManager $localeConfig; * The locale configuration manager object. */ - public function __construct($definition, $name, $langcode, LocaleConfigManager $localeConfig) { + public function __construct(DataDefinitionInterface $definition, $name, $langcode, LocaleConfigManager $localeConfig) { parent::__construct($definition, $name); $this->langcode = $langcode; $this->localeConfig = $localeConfig;