Skip to content
Snippets Groups Projects
Verified Commit 2dc7b233 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3406487 by Wim Leers, phenaproxima: Consistently use "dynamic type...

Issue #3406487 by Wim Leers, phenaproxima: Consistently use "dynamic type name" and "expression" instead of "variable value" in TypedConfigManager's terminology
parent 9cf73365
No related branches found
No related tags found
No related merge requests found
......@@ -119,8 +119,8 @@ protected function getDefinedKeys(): array {
* - the corresponding value an array of the additional mapping keys that
* are supported for this resolved type
*
* @see \Drupal\Core\Config\TypedConfigManager::replaceName()
* @see \Drupal\Core\Config\TypedConfigManager::replaceVariable()
* @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 {
......
......@@ -104,7 +104,7 @@ public function buildDataDefinition(array $definition, $value, $name = NULL, $pa
if (isset($name)) {
$replace['%key'] = $name;
}
$type = $this->replaceName($type, $replace);
$type = $this->resolveDynamicTypeName($type, $replace);
// Remove the type from the definition so that it is replaced with the
// concrete type from schema definitions.
unset($definition['type']);
......@@ -150,7 +150,7 @@ protected function determineType($base_plugin_id, array $definitions) {
}
/**
* Gets a schema definition with replacements for dynamic names.
* Gets a schema definition with replacements for dynamic type names.
*
* @param string $base_plugin_id
* A plugin ID.
......@@ -177,7 +177,7 @@ protected function getDefinitionWithReplacements($base_plugin_id, array $replace
// Replace dynamic portions of the definition type.
if (!empty($replacements) && strpos($definition['type'], ']')) {
$sub_type = $this->determineType($this->replaceName($definition['type'], $replacements), $definitions);
$sub_type = $this->determineType($this->resolveDynamicTypeName($definition['type'], $replacements), $definitions);
$sub_definition = $definitions[$sub_type];
if (isset($definitions[$sub_type]['type'])) {
$sub_merge = $this->getDefinition($definitions[$sub_type]['type'], $exception_on_invalid);
......@@ -282,39 +282,69 @@ protected function getFallbackName($name) {
}
/**
* Replaces variables in configuration name.
* Replaces dynamic type expressions in configuration type.
*
* The configuration name may contain one or more variables to be replaced,
* enclosed in square brackets like '[name]' and will follow the replacement
* rules defined by the replaceVariable() method.
* The configuration type name may contain one or more expressions to be
* replaced, enclosed in square brackets like '[name]' or '[%parent.id]' and
* will follow the replacement rules defined by the resolveExpression()
* method.
*
* @param string $name
* Configuration name with variables in square brackets.
* @param mixed $data
* @param string $type
* Configuration type, potentially with expressions in square brackets.
* @param array $data
* Configuration data for the element.
*
* @return string
* Configuration name with variables replaced.
* Configuration type name with all expressions resolved.
*/
protected function replaceName($name, $data) {
if (preg_match_all("/\[(.*)\]/U", $name, $matches)) {
protected function resolveDynamicTypeName(string $type, array $data): string {
// Parse the expressions in the dynamic type, if any.
if (preg_match_all("/\[(.*)\]/U", $type, $matches)) {
// Build our list of '[value]' => replacement.
$replace = [];
foreach (array_combine($matches[0], $matches[1]) as $key => $value) {
$replace[$key] = $this->replaceVariable($value, $data);
$replace[$key] = $this->resolveExpression($value, $data);
}
return strtr($name, $replace);
return strtr($type, $replace);
}
else {
return $name;
// No expressions: nothing to resolve.
return $type;
}
}
/**
* Replaces variable values in included names with configuration data.
* Replaces dynamic type expressions in configuration type.
*
* The configuration type name may contain one or more expressions to be
* replaced, enclosed in square brackets like '[name]' or '[%parent.id]' and
* will follow the replacement rules defined by the resolveExpression()
* method.
*
* @param string $name
* Configuration type, potentially with expressions in square brackets.
* @param array $data
* Configuration data for the element.
*
* @return string
* Configuration type name with all expressions resolved.
*
* @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use
* ::resolveDynamicTypeName() instead.
*
* @see https://www.drupal.org/node/3408266
*/
protected function replaceName($name, $data) {
@trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use ::resolveDynamicTypeName() instead. See https://www.drupal.org/node/3408266', E_USER_DEPRECATED);
return $this->resolveDynamicTypeName($name, $data);
}
/**
* Resolves a dynamic type expression using configuration data.
*
* Variable values are nested configuration keys that will be replaced by
* their value or some of these special strings:
* Dynamic type names are nested configuration keys containing expressions to
* be replaced by the value at the property path that the expression is
* pointing at. The expression may contain the following special strings:
* - '%key', will be replaced by the element's key.
* - '%parent', to reference the parent element.
* - '%type', to reference the schema definition type. Can only be used in
......@@ -324,7 +354,7 @@ protected function replaceName($name, $data) {
* patterns like '%parent.name' which references the 'name' value of the
* parent element.
*
* Example patterns:
* Example expressions:
* - 'name.subkey', indicates a nested value of the current element.
* - '%parent.name', will be replaced by the 'name' value of the parent.
* - '%parent.%key', will be replaced by the parent element's key.
......@@ -332,29 +362,33 @@ protected function replaceName($name, $data) {
* - '%parent.%parent.%type', will be replaced by the schema type of the
* parent's parent.
*
* @param string $value
* Variable value to be replaced.
* @param mixed $data
* @param string $expression
* Expression to be resolved.
* @param array $data
* Configuration data for the element.
*
* @return string
* The replaced value if a replacement found or the original value if not.
* The value the expression resolves to, or the given expression if it
* cannot be resolved.
*
* @todo Validate the expression in https://www.drupal.org/project/drupal/issues/3392903
*/
protected function replaceVariable($value, $data) {
$parts = explode('.', $value);
protected function resolveExpression(string $expression, array $data): string {
assert(!str_contains($expression, '[') && !str_contains($expression, ']'));
$parts = explode('.', $expression);
// Process each value part, one at a time.
while ($name = array_shift($parts)) {
if (!is_array($data) || !isset($data[$name])) {
// Key not found, return original value
return $value;
return $expression;
}
elseif (!$parts) {
$value = $data[$name];
if (is_bool($value)) {
$value = (int) $value;
$expression = $data[$name];
if (is_bool($expression)) {
$expression = (int) $expression;
}
// If no more parts left, this is the final property.
return (string) $value;
return (string) $expression;
}
else {
// Get nested value and continue processing.
......@@ -375,6 +409,51 @@ protected function replaceVariable($value, $data) {
}
}
}
// Satisfy PHPStan, which cannot interpret the loop.
return $expression;
}
/**
* Resolves a dynamic type expression using configuration data.
*
* Dynamic type names are nested configuration keys containing expressions to
* be replaced by the value at the property path that the expression is
* pointing at. The expression may contain the following special strings:
* - '%key', will be replaced by the element's key.
* - '%parent', to reference the parent element.
* - '%type', to reference the schema definition type. Can only be used in
* combination with %parent.
*
* There may be nested configuration keys separated by dots or more complex
* patterns like '%parent.name' which references the 'name' value of the
* parent element.
*
* Example expressions:
* - 'name.subkey', indicates a nested value of the current element.
* - '%parent.name', will be replaced by the 'name' value of the parent.
* - '%parent.%key', will be replaced by the parent element's key.
* - '%parent.%type', will be replaced by the schema type of the parent.
* - '%parent.%parent.%type', will be replaced by the schema type of the
* parent's parent.
*
* @param string $value
* Expression to be resolved.
* @param array $data
* Configuration data for the element.
*
* @return string
* The value the expression resolves to, or the given expression if it
* cannot be resolved.
*
* @deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use
* ::resolveExpression() instead.
*
* @see https://www.drupal.org/node/3408266
*/
protected function replaceVariable($value, $data) {
@trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:11.0.0. Use ::resolveExpression() instead. See https://www.drupal.org/node/3408266', E_USER_DEPRECATED);
return $this->resolveExpression($value, $data);
}
/**
......
......@@ -344,11 +344,6 @@ parameters:
count: 1
path: lib/Drupal/Core/Config/ExtensionInstallStorage.php
-
message: "#^Method Drupal\\\\Core\\\\Config\\\\TypedConfigManager\\:\\:replaceVariable\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: lib/Drupal/Core/Config/TypedConfigManager.php
-
message: """
#^Fetching deprecated class constant RETURN_AFFECTED of class Drupal\\\\Core\\\\Database\\\\Database\\:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment