class Mapping
Same name in this branch
- 11.x core/modules/views/src/Plugin/views/style/Mapping.php \Drupal\views\Plugin\views\style\Mapping
Same name in other branches
- 9 core/modules/views/src/Plugin/views/style/Mapping.php \Drupal\views\Plugin\views\style\Mapping
- 9 core/lib/Drupal/Core/Config/Schema/Mapping.php \Drupal\Core\Config\Schema\Mapping
- 8.9.x core/modules/views/src/Plugin/views/style/Mapping.php \Drupal\views\Plugin\views\style\Mapping
- 8.9.x core/lib/Drupal/Core/Config/Schema/Mapping.php \Drupal\Core\Config\Schema\Mapping
- 10 core/modules/views/src/Plugin/views/style/Mapping.php \Drupal\views\Plugin\views\style\Mapping
- 10 core/lib/Drupal/Core/Config/Schema/Mapping.php \Drupal\Core\Config\Schema\Mapping
Defines a mapping configuration element.
This object may contain any number and type of nested properties and each property key may have its own definition in the 'mapping' property of the configuration schema.
Properties in the configuration value that are not defined in the mapping will get the 'undefined' data type.
Read https://www.drupal.org/node/1905070 for more details about configuration schema, types and type resolution.
Hierarchy
- class \Drupal\Core\TypedData\TypedData implements \Drupal\Core\TypedData\TypedDataInterface, \Drupal\Component\Plugin\PluginInspectionInterface uses \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\TypedData\TypedDataTrait
- class \Drupal\Core\Config\Schema\Element extends \Drupal\Core\TypedData\TypedData
- class \Drupal\Core\Config\Schema\ArrayElement extends \Drupal\Core\Config\Schema\Element implements \Drupal\Core\Config\Schema\IteratorAggregate, \Drupal\Core\Config\Schema\TypedConfigInterface, \Drupal\Core\TypedData\ComplexDataInterface
- class \Drupal\Core\Config\Schema\Mapping extends \Drupal\Core\Config\Schema\ArrayElement
- class \Drupal\Core\Config\Schema\ArrayElement extends \Drupal\Core\Config\Schema\Element implements \Drupal\Core\Config\Schema\IteratorAggregate, \Drupal\Core\Config\Schema\TypedConfigInterface, \Drupal\Core\TypedData\ComplexDataInterface
- class \Drupal\Core\Config\Schema\Element extends \Drupal\Core\TypedData\TypedData
Expanded class hierarchy of Mapping
11 files declare their use of Mapping
- ConfigActionManager.php in core/
lib/ Drupal/ Core/ Config/ Action/ ConfigActionManager.php - ConfigEntityAdapterTest.php in core/
tests/ Drupal/ KernelTests/ Core/ Entity/ ConfigEntityAdapterTest.php - ConfigEntityValidationTestBase.php in core/
tests/ Drupal/ KernelTests/ Core/ Config/ ConfigEntityValidationTestBase.php - ConfigMapperManagerTest.php in core/
modules/ config_translation/ tests/ src/ Unit/ ConfigMapperManagerTest.php - ConfigSchemaTest.php in core/
tests/ Drupal/ KernelTests/ Core/ Config/ ConfigSchemaTest.php
94 string references to 'Mapping'
- action_bulk_test.schema.yml in core/
modules/ views/ tests/ modules/ action_bulk_test/ config/ schema/ action_bulk_test.schema.yml - core/modules/views/tests/modules/action_bulk_test/config/schema/action_bulk_test.schema.yml
- action_test.schema.yml in core/
modules/ system/ tests/ modules/ action_test/ config/ schema/ action_test.schema.yml - core/modules/system/tests/modules/action_test/config/schema/action_test.schema.yml
- book.schema.yml in core/
modules/ book/ config/ schema/ book.schema.yml - core/modules/book/config/schema/book.schema.yml
- ckeditor5.pair.schema.yml in core/
modules/ ckeditor5/ config/ schema/ ckeditor5.pair.schema.yml - core/modules/ckeditor5/config/schema/ckeditor5.pair.schema.yml
- ckeditor5.schema.yml in core/
modules/ ckeditor5/ config/ schema/ ckeditor5.schema.yml - core/modules/ckeditor5/config/schema/ckeditor5.schema.yml
File
-
core/
lib/ Drupal/ Core/ Config/ Schema/ Mapping.php, line 23
Namespace
Drupal\Core\Config\SchemaView source
class Mapping extends ArrayElement {
/**
* {@inheritdoc}
*/
public function __construct(DataDefinitionInterface $definition, $name = NULL, ?TypedDataInterface $parent = NULL) {
assert($definition instanceof MapDataDefinition);
// Validate basic structure.
foreach ($definition['mapping'] as $key => $key_definition) {
// Guide developers when a config schema definition is wrong.
if (!is_array($key_definition)) {
if (!$parent) {
throw new \LogicException(sprintf("The mapping definition at `%s` is invalid: its `%s` key contains a %s. It must be an array.", $name, $key, gettype($key_definition)));
}
else {
throw new \LogicException(sprintf("The mapping definition at `%s:%s` is invalid: its `%s` key contains a %s. It must be an array.", $parent->getPropertyPath(), $name, $key, gettype($key_definition)));
}
}
}
$this->processRequiredKeyFlags($definition);
parent::__construct($definition, $name, $parent);
}
/**
* {@inheritdoc}
*/
protected function getElementDefinition($key) {
$value = $this->value[$key] ?? NULL;
$definition = $this->definition['mapping'][$key] ?? [];
return $this->buildDataDefinition($definition, $value, $key);
}
/**
* Gets all keys allowed in this mapping.
*
* @return string[]
* A list of keys allowed in this mapping.
*/
public function getValidKeys() : array {
$all_keys = $this->getDefinedKeys();
return array_keys($all_keys);
}
/**
* Gets all required keys in this mapping.
*
* @return string[]
* A list of keys required in this mapping.
*/
public function getRequiredKeys() : array {
$all_keys = $this->getDefinedKeys();
$required_keys = array_filter($all_keys, fn(array $schema_definition): bool => $schema_definition['requiredKey']);
return array_keys($required_keys);
}
/**
* Gets the keys defined for this mapping (locally defined + inherited).
*
* @return array
* Raw schema definitions: keys are mapping keys, values are their
* definitions.
*/
protected function getDefinedKeys() : array {
$definition = $this->getDataDefinition();
return $definition->toArray()['mapping'];
}
/**
* Gets all dynamically valid keys.
*
* When the `type` of the mapping is dynamic itself. For example: the settings
* associated with a FieldConfig depend on what kind of field it is (i.e.,
* which field plugin it uses).
*
* Other examples:
* - CKEditor 5 uses 'ckeditor5.plugin.[%key]'; the mapping is stored in a
* sequence, and `[%key]` is replaced by the mapping's key in that sequence.
* - third party settings use '[%parent.%parent.%type].third_party.[%key]';
* `[%parent.%parent.%type]` is replaced by the type of the mapping two
* levels up. For example, 'node.type.third_party.[%key]'.
* - field instances' default values have a type of
* 'field.value.[%parent.%parent.field_type]'. This uses the value of the
* `field_type` key from the mapping two levels up.
* - Views filters have a type of 'views.filter.[plugin_id]'; `[plugin_id]` is
* replaced by the value of the mapping's `plugin_id` key.
*
* In each of these examples, the mapping may have keys that are dynamically
* valid, meaning that which keys are considered valid may depend on other
* values in the tree.
*
* @return string[][]
* A list of dynamically valid keys. An array with:
* - a key for every possible resolved type
* - the corresponding value an array of the additional mapping keys that
* are supported for this resolved type
*
* @see \Drupal\Core\Config\TypedConfigManager::resolveDynamicTypeName()
* @see \Drupal\Core\Config\TypedConfigManager::resolveExpression()
* @see https://www.drupal.org/files/ConfigSchemaCheatSheet2.0.pdf
*/
public function getDynamicallyValidKeys() : array {
$parent_data_def = $this->getParent()?->getDataDefinition();
if ($parent_data_def === NULL) {
return [];
}
// Use the parent data definition to determine the type of this mapping
// (including the dynamic placeholders). For example:
// - `editor.settings.[%parent.editor]`
// - `editor.image_upload_settings.[status]`.
$original_mapping_type = match (TRUE) { $parent_data_def instanceof MapDataDefinition => $parent_data_def->toArray()['mapping'][$this->getName()]['type'],
$parent_data_def instanceof SequenceDataDefinition => $parent_data_def->toArray()['sequence']['type'],
default => throw new \LogicException('Invalid config schema detected.'),
};
// If this mapping's type isn't dynamic, there's nothing to do.
if (!str_contains($original_mapping_type, ']')) {
return [];
}
elseif (str_starts_with($original_mapping_type, '[')) {
return [];
}
// Expand the dynamic placeholders to find all mapping types derived from
// the original mapping type. To continue the previous example:
// - `editor.settings.unicorn`
// - `editor.image_upload_settings.*`
// - `editor.image_upload_settings.1`
$possible_types = $this->getPossibleTypes($original_mapping_type);
// TRICKY: it is tempting to not consider this a dynamic type if only one
// concrete type exists. But that would lead to different validation errors
// when modules are installed or uninstalled.
assert(!empty($possible_types));
// Determine all valid keys, across all possible types.
$typed_data_manager = $this->getTypedDataManager();
$all_type_definitions = $typed_data_manager->getDefinitions();
$possible_type_definitions = array_intersect_key($all_type_definitions, array_fill_keys($possible_types, TRUE));
// TRICKY: \Drupal\Core\Config\TypedConfigManager::getDefinition() does the
// necessary resolving, but TypedConfigManager::getDefinitions() does not! 🤷♂️
// @see \Drupal\Core\Config\TypedConfigManager::getDefinitionWithReplacements()
// @see ::getValidKeys()
$valid_keys_per_type = [];
foreach (array_keys($possible_type_definitions) as $possible_type_name) {
$valid_keys_per_type[$possible_type_name] = array_keys($typed_data_manager->getDefinition($possible_type_name)['mapping'] ?? []);
}
// From all valid keys across all types, get the ones for the fallback type:
// its keys are inherited by all type definitions and are therefore always
// ("statically") valid. Not all types have a fallback type.
// @see \Drupal\Core\Config\TypedConfigManager::getDefinitionWithReplacements()
$fallback_type = $typed_data_manager->findFallback($original_mapping_type);
$valid_keys_everywhere = array_intersect_key($valid_keys_per_type, [
$fallback_type => NULL,
]);
assert(count($valid_keys_everywhere) <= 1);
$statically_required_keys = NestedArray::mergeDeepArray($valid_keys_everywhere);
// Now that statically valid keys are known, determine which valid keys are
// only valid in *some* cases: remove the statically valid keys from every
// per-type array of valid keys.
$valid_keys_some = array_diff_key($valid_keys_per_type, $valid_keys_everywhere);
$valid_keys_some_processed = array_map(fn(array $keys) => array_values(array_filter($keys, fn(string $key) => !in_array($key, $statically_required_keys, TRUE))), $valid_keys_some);
return $valid_keys_some_processed;
}
/**
* Gets all optional keys in this mapping.
*
* @return string[]
* A list of optional keys given the values in this mapping.
*/
public function getOptionalKeys() : array {
return array_values(array_diff($this->getValidKeys(), $this->getRequiredKeys()));
}
/**
* Validates optional `requiredKey` flags, guarantees one will be set.
*
* For each key-value pair:
* - If the `requiredKey` flag is set, it must be `false`, to avoid pointless
* information in the schema.
* - If the `requiredKey` flag is not set and the `deprecated` flag is set,
* this will set `requiredKey: false`: deprecated keys are always optional.
* - If the `requiredKey` flag is not set, nor the `deprecated` flag,
* will set `requiredKey: true`.
*
* @param \Drupal\Core\TypedData\MapDataDefinition $definition
* The config schema definition for a `type: mapping`.
*
* @return void
*
* @throws \LogicException
* Thrown when `requiredKey: true` is specified.
*/
protected function processRequiredKeyFlags(MapDataDefinition $definition) : void {
foreach ($definition['mapping'] as $key => $key_definition) {
// Validates `requiredKey` flag in mapping definitions.
if (array_key_exists('requiredKey', $key_definition) && $key_definition['requiredKey'] !== FALSE) {
throw new \LogicException('The `requiredKey` flag must either be omitted or have `false` as the value.');
}
// Generates the `requiredKey` flag if it is not set.
if (!array_key_exists('requiredKey', $key_definition)) {
// Required by default, unless this key is marked as deprecated.
// @see https://www.drupal.org/node/3129881
$definition['mapping'][$key]['requiredKey'] = !array_key_exists('deprecated', $key_definition);
}
}
}
/**
* Returns all possible types for the type with the given name.
*
* @param string $name
* Configuration name or key.
*
* @return string[]
* All possible types for a given type. For example,
* `core_date_format_pattern.[%parent.locked]` will return:
* - `core_date_format_pattern.0`
* - `core_date_format_pattern.1`
* If a fallback name is available, that will be returned too. In this
* example, that would be `core_date_format_pattern.*`.
*/
protected function getPossibleTypes(string $name) : array {
// First, parse from e.g.
// `module.something.foo_[%parent.locked]`
// this:
// `[%parent.locked]`
// or from
// `[%parent.%parent.%type].third_party.[%key]`
// this:
// `[%parent.%parent.%type]` and `[%key]`.
// And collapse all these to just `[]`.
// @see \Drupal\Core\Config\TypedConfigManager::replaceVariable()
$matches = [];
if (preg_match_all('/(\\[[^\\]]+\\])/', $name, $matches) >= 1) {
$name = str_replace($matches[0], '[]', $name);
}
// Then, replace all `[]` occurrences with `.*` and escape all periods for
// use in a regex. So:
// `module\.something\.foo_.*`
// or
// `.*\.third_party\..*`
$regex = str_replace([
'.',
'[]',
], [
'\\.',
'.*',
], $name);
// Now find all possible types:
// 1. `module.something.foo_foo`, `module.something.foo_bar`, etc.
$possible_types = array_filter(array_keys($this->getTypedDataManager()
->getDefinitions()), fn(string $type) => preg_match("/^{$regex}\$/", $type) === 1);
// 2. The fallback: `module.something.*` — if no concrete definition for it
// exists.
$fallback_type = $this->getTypedDataManager()
->findFallback($name);
if ($fallback_type && !in_array($fallback_type, $possible_types, TRUE)) {
$possible_types[] = $fallback_type;
}
return $possible_types;
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
ArrayElement::$elements | protected | property | Parsed elements. | ||
ArrayElement::buildDataDefinition | protected | function | Creates a new data definition object from an array and configuration. | ||
ArrayElement::createElement | protected | function | Creates a contained typed configuration object. | ||
ArrayElement::get | public | function | Gets a contained typed configuration element. | Overrides TypedConfigInterface::get | |
ArrayElement::getAllKeys | protected | function | Gets valid configuration data keys. | ||
ArrayElement::getElements | public | function | Gets an array of contained elements. | Overrides TypedConfigInterface::getElements | |
ArrayElement::getIterator | public | function | |||
ArrayElement::getProperties | public | function | Gets an array of property objects. | Overrides ComplexDataInterface::getProperties | |
ArrayElement::hasTranslatableElements | public | function | Determines if there is a translatable value. | ||
ArrayElement::isEmpty | public | function | Determines whether the data structure is empty. | Overrides TypedConfigInterface::isEmpty | |
ArrayElement::isNullable | public | function | Determines if this element allows NULL as a value. | ||
ArrayElement::onChange | public | function | React to changes to a child property or item. | Overrides TraversableTypedDataInterface::onChange | |
ArrayElement::parse | protected | function | Builds an array of contained elements. | ||
ArrayElement::set | public | function | Sets a property value. | Overrides ComplexDataInterface::set | |
ArrayElement::toArray | public | function | Returns an array of all property values. | Overrides TypedConfigInterface::toArray | |
DependencySerializationTrait::$_entityStorages | protected | property | |||
DependencySerializationTrait::$_serviceIds | protected | property | |||
DependencySerializationTrait::__sleep | public | function | 1 | ||
DependencySerializationTrait::__wakeup | public | function | 2 | ||
Element::$value | protected | property | The configuration value. | ||
Element::getTypedDataManager | public | function | Gets the typed configuration manager. | Overrides TypedDataTrait::getTypedDataManager | |
Element::setTypedDataManager | public | function | Sets the typed config manager. | Overrides TypedDataTrait::setTypedDataManager | |
Mapping::getDefinedKeys | protected | function | Gets the keys defined for this mapping (locally defined + inherited). | ||
Mapping::getDynamicallyValidKeys | public | function | Gets all dynamically valid keys. | ||
Mapping::getElementDefinition | protected | function | Gets data definition object for contained element. | Overrides ArrayElement::getElementDefinition | |
Mapping::getOptionalKeys | public | function | Gets all optional keys in this mapping. | ||
Mapping::getPossibleTypes | protected | function | Returns all possible types for the type with the given name. | ||
Mapping::getRequiredKeys | public | function | Gets all required keys in this mapping. | ||
Mapping::getValidKeys | public | function | Gets all keys allowed in this mapping. | ||
Mapping::processRequiredKeyFlags | protected | function | Validates optional `requiredKey` flags, guarantees one will be set. | ||
Mapping::__construct | public | function | Constructs a TypedData object given its definition and context. | Overrides TypedData::__construct | |
StringTranslationTrait::$stringTranslation | protected | property | The string translation service. | 3 | |
StringTranslationTrait::formatPlural | protected | function | Formats a string containing a count of items. | ||
StringTranslationTrait::getNumberOfPlurals | protected | function | Returns the number of plurals supported by a given language. | ||
StringTranslationTrait::getStringTranslation | protected | function | Gets the string translation service. | ||
StringTranslationTrait::setStringTranslation | public | function | Sets the string translation service to use. | 2 | |
StringTranslationTrait::t | protected | function | Translates a string to the current language or to a given language. | ||
TypedData::$definition | protected | property | The data definition. | 1 | |
TypedData::$name | protected | property | The property name. | ||
TypedData::$parent | protected | property | The parent typed data object. | ||
TypedData::applyDefaultValue | public | function | Applies the default value. | Overrides TypedDataInterface::applyDefaultValue | 3 |
TypedData::createInstance | public static | function | Constructs a TypedData object given its definition and context. | Overrides TypedDataInterface::createInstance | |
TypedData::getConstraints | public | function | Gets a list of validation constraints. | Overrides TypedDataInterface::getConstraints | 8 |
TypedData::getDataDefinition | public | function | Gets the data definition. | Overrides TypedDataInterface::getDataDefinition | |
TypedData::getName | public | function | Returns the name of a property or item. | Overrides TypedDataInterface::getName | |
TypedData::getParent | public | function | Returns the parent data structure; i.e. either complex data or a list. | Overrides TypedDataInterface::getParent | |
TypedData::getPluginDefinition | public | function | Gets the definition of the plugin implementation. | Overrides PluginInspectionInterface::getPluginDefinition | |
TypedData::getPluginId | public | function | Gets the plugin ID of the plugin instance. | Overrides PluginInspectionInterface::getPluginId | |
TypedData::getPropertyPath | public | function | Returns the property path of the data. | Overrides TypedDataInterface::getPropertyPath | |
TypedData::getRoot | public | function | Returns the root of the typed data tree. | Overrides TypedDataInterface::getRoot | |
TypedData::getString | public | function | Returns a string representation of the data. | Overrides TypedDataInterface::getString | 6 |
TypedData::getValue | public | function | Gets the data value. | Overrides TypedDataInterface::getValue | 10 |
TypedData::setContext | public | function | Sets the context of a property or item via a context aware parent. | Overrides TypedDataInterface::setContext | |
TypedData::setValue | public | function | Sets the data value. | Overrides TypedDataInterface::setValue | 10 |
TypedData::validate | public | function | Validates the currently set data value. | Overrides TypedDataInterface::validate | |
TypedDataTrait::$typedDataManager | protected | property | The typed data manager used for creating the data types. |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.