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
Loading
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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 {
+110 −31
Original line number Diff line number Diff line
@@ -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);
  }

  /**
+0 −5
Original line number Diff line number Diff line
@@ -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\\: