Issue #2392057 by tim.plunkett, vasi, benjy, alexpott, Gábor Hojtsy, YesCT: Config schema fails to expand dynamic top-level types
parent
5fa8ed087b
commit
9ccbfdaca4
|
@ -86,6 +86,7 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
||||||
// Add default values for data type and replace variables.
|
// Add default values for data type and replace variables.
|
||||||
$definition += array('type' => 'undefined');
|
$definition += array('type' => 'undefined');
|
||||||
|
|
||||||
|
$replace = [];
|
||||||
$type = $definition['type'];
|
$type = $definition['type'];
|
||||||
if (strpos($type, ']')) {
|
if (strpos($type, ']')) {
|
||||||
// Replace variable names in definition.
|
// Replace variable names in definition.
|
||||||
|
@ -102,7 +103,7 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
||||||
unset($definition['type']);
|
unset($definition['type']);
|
||||||
}
|
}
|
||||||
// Add default values from type definition.
|
// Add default values from type definition.
|
||||||
$definition += $this->getDefinition($type);
|
$definition += $this->getDefinitionWithReplacements($type, $replace);
|
||||||
|
|
||||||
$data_definition = $this->createDataDefinition($definition['type']);
|
$data_definition = $this->createDataDefinition($definition['type']);
|
||||||
|
|
||||||
|
@ -116,10 +117,17 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* Determines the typed config type for a plugin ID.
|
||||||
|
*
|
||||||
|
* @param string $base_plugin_id
|
||||||
|
* The plugin ID.
|
||||||
|
* @param array $definitions
|
||||||
|
* An array of typed config definitions.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The typed config type for the given plugin ID.
|
||||||
*/
|
*/
|
||||||
public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) {
|
protected function determineType($base_plugin_id, array $definitions) {
|
||||||
$definitions = $this->getDefinitions();
|
|
||||||
if (isset($definitions[$base_plugin_id])) {
|
if (isset($definitions[$base_plugin_id])) {
|
||||||
$type = $base_plugin_id;
|
$type = $base_plugin_id;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +139,27 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
||||||
// If we don't have definition, return the 'undefined' element.
|
// If we don't have definition, return the 'undefined' element.
|
||||||
$type = 'undefined';
|
$type = 'undefined';
|
||||||
}
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a schema definition with replacements for dynamic names.
|
||||||
|
*
|
||||||
|
* @param string $base_plugin_id
|
||||||
|
* A plugin ID.
|
||||||
|
* @param array $replacements
|
||||||
|
* An array of replacements for dynamic type names.
|
||||||
|
* @param bool $exception_on_invalid
|
||||||
|
* (optional) This parameter is passed along to self::getDefinition().
|
||||||
|
* However, self::getDefinition() does not respect this parameter, so it is
|
||||||
|
* effectively useless in this context.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* A schema definition array.
|
||||||
|
*/
|
||||||
|
protected function getDefinitionWithReplacements($base_plugin_id, array $replacements, $exception_on_invalid = TRUE) {
|
||||||
|
$definitions = $this->getDefinitions();
|
||||||
|
$type = $this->determineType($base_plugin_id, $definitions);
|
||||||
$definition = $definitions[$type];
|
$definition = $definitions[$type];
|
||||||
// Check whether this type is an extension of another one and compile it.
|
// Check whether this type is an extension of another one and compile it.
|
||||||
if (isset($definition['type'])) {
|
if (isset($definition['type'])) {
|
||||||
|
@ -138,6 +167,15 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
||||||
// Preserve integer keys on merge, so sequence item types can override
|
// Preserve integer keys on merge, so sequence item types can override
|
||||||
// parent settings as opposed to adding unused second, third, etc. items.
|
// parent settings as opposed to adding unused second, third, etc. items.
|
||||||
$definition = NestedArray::mergeDeepArray(array($merge, $definition), TRUE);
|
$definition = NestedArray::mergeDeepArray(array($merge, $definition), TRUE);
|
||||||
|
|
||||||
|
// Replace dynamic portions of the definition type.
|
||||||
|
if (!empty($replacements) && strpos($definition['type'], ']')) {
|
||||||
|
$sub_type = $this->determineType($this->replaceName($definition['type'], $replacements), $definitions);
|
||||||
|
// Merge the newly determined subtype definition with the original
|
||||||
|
// definition.
|
||||||
|
$definition = NestedArray::mergeDeepArray([$definitions[$sub_type], $definition], TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
// Unset type so we try the merge only once per type.
|
// Unset type so we try the merge only once per type.
|
||||||
unset($definition['type']);
|
unset($definition['type']);
|
||||||
$this->definitions[$type] = $definition;
|
$this->definitions[$type] = $definition;
|
||||||
|
@ -150,6 +188,13 @@ class TypedConfigManager extends TypedDataManager implements TypedConfigManagerI
|
||||||
return $definition;
|
return $definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) {
|
||||||
|
return $this->getDefinitionWithReplacements($base_plugin_id, [], $exception_on_invalid);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -506,4 +506,70 @@ class ConfigSchemaTest extends KernelTestBase {
|
||||||
$this->assertEqual($definitions['config_schema_test.hook']['additional_metadata'], 'new schema info');
|
$this->assertEqual($definitions['config_schema_test.hook']['additional_metadata'], 'new schema info');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests saving config when the type is wrapped by a dynamic type.
|
||||||
|
*/
|
||||||
|
public function testConfigSaveWithWrappingSchema() {
|
||||||
|
$untyped_values = [
|
||||||
|
'tests' => [
|
||||||
|
[
|
||||||
|
'wrapper_value' => 'foo',
|
||||||
|
'plugin_id' => 'wrapper:foo',
|
||||||
|
'internal_value' => 100,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$typed_values = [
|
||||||
|
'tests' => [
|
||||||
|
[
|
||||||
|
'wrapper_value' => 'foo',
|
||||||
|
'plugin_id' => 'wrapper:foo',
|
||||||
|
'internal_value' => '100',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Save config which has a schema that enforces types.
|
||||||
|
\Drupal::configFactory()->getEditable('wrapping.config_schema_test.plugin_types')
|
||||||
|
->setData($untyped_values)
|
||||||
|
->save();
|
||||||
|
$this->assertIdentical(\Drupal::config('wrapping.config_schema_test.plugin_types')
|
||||||
|
->get(), $typed_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests dynamic config schema type with multiple sub-key references.
|
||||||
|
*/
|
||||||
|
public function testConfigSaveWithWrappingSchemaDoubleBrackets() {
|
||||||
|
$untyped_values = [
|
||||||
|
'tests' => [
|
||||||
|
[
|
||||||
|
'wrapper_value' => 'foo',
|
||||||
|
'foo' => 'cat',
|
||||||
|
'bar' => 'dog',
|
||||||
|
'another_key' => 100,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$typed_values = [
|
||||||
|
'tests' => [
|
||||||
|
[
|
||||||
|
'wrapper_value' => 'foo',
|
||||||
|
'foo' => 'cat',
|
||||||
|
'bar' => 'dog',
|
||||||
|
'another_key' => '100',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Save config which has a schema that enforces types.
|
||||||
|
\Drupal::configFactory()->getEditable('wrapping.config_schema_test.double_brackets')
|
||||||
|
->setData($untyped_values)
|
||||||
|
->save();
|
||||||
|
$this->assertIdentical(\Drupal::config('wrapping.config_schema_test.double_brackets')
|
||||||
|
->get(), $typed_values);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,3 +213,50 @@ config_test.dynamic.*.third_party.config_schema_test:
|
||||||
type: integer
|
type: integer
|
||||||
string:
|
string:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
wrapping.config_schema_test.plugin_types:
|
||||||
|
type: config_object
|
||||||
|
mapping:
|
||||||
|
tests:
|
||||||
|
type: sequence
|
||||||
|
sequence:
|
||||||
|
- type: wrapping.test.plugin_types.[plugin_id]
|
||||||
|
|
||||||
|
wrapping.test.plugin_types.*:
|
||||||
|
type: test.plugin_types.[plugin_id]
|
||||||
|
mapping:
|
||||||
|
wrapper_value:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
test.plugin_types.wrapper:*:
|
||||||
|
type: test.plugin_types
|
||||||
|
mapping:
|
||||||
|
internal_value:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
wrapping.config_schema_test.double_brackets:
|
||||||
|
type: config_object
|
||||||
|
mapping:
|
||||||
|
tests:
|
||||||
|
type: sequence
|
||||||
|
sequence:
|
||||||
|
- type: wrapping.test.double_brackets.[another_key]
|
||||||
|
|
||||||
|
wrapping.test.double_brackets.*:
|
||||||
|
type: test.double_brackets.[foo].[bar]
|
||||||
|
mapping:
|
||||||
|
wrapper_value:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
test.double_brackets.cat.dog:
|
||||||
|
type: test.double_brackets
|
||||||
|
mapping:
|
||||||
|
another_key:
|
||||||
|
type: string
|
||||||
|
foo:
|
||||||
|
type: string
|
||||||
|
bar:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
test.double_brackets.*:
|
||||||
|
type: mapping
|
||||||
|
|
Loading…
Reference in New Issue