Unverified Commit a2d4afd1 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3497061 by phenaproxima, alexpott: Allow recipe input values in array keys

(cherry picked from commit 5db48676)
parent 1f559ea8
Loading
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@

namespace Drupal\Core\Recipe;

use Drupal\Core\Config\Action\ConfigActionException;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\InstallStorage;
use Drupal\Core\Config\StorageInterface;
@@ -93,11 +95,14 @@ protected static function processInstall(InstallConfigurator $install, StorageIn
   *   The recipe being applied.
   */
  protected static function processConfiguration(Recipe $recipe): void {
    /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
    $config_manager = \Drupal::service(ConfigManagerInterface::class);

    $config_installer = new RecipeConfigInstaller(
      \Drupal::service('config.factory'),
      \Drupal::service('config.storage'),
      \Drupal::service('config.typed'),
      \Drupal::service('config.manager'),
      $config_manager,
      \Drupal::service('event_dispatcher'),
      NULL,
      \Drupal::service('extension.path.resolver'));
@@ -118,6 +123,13 @@ protected static function processConfiguration(Recipe $recipe): void {
      /** @var \Drupal\Core\Config\Action\ConfigActionManager $config_action_manager */
      $config_action_manager = \Drupal::service('plugin.manager.config_action');
      foreach ($config->config['actions'] as $config_name => $actions) {
        // If this config name contains an input value, it must begin with the
        // config prefix of a known entity type.
        if (str_contains($config_name, '${') && empty($config_manager->getEntityTypeIdByName($config_name))) {
          throw new ConfigActionException("The entity type for the config name '$config_name' could not be identified.");
        }
        $config_name = str_replace($keys, $replace, $config_name);

        foreach ($actions as $action_id => $data) {
          $config_action_manager->applyAction($action_id, $config_name, static::replaceInputValues($data, $replace));
        }
+43 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

use Drupal\Component\Uuid\UuidInterface;
use Drupal\contact\Entity\ContactForm;
use Drupal\Core\Config\Action\ConfigActionException;
use Drupal\Core\Recipe\ConsoleInputCollector;
use Drupal\Core\Recipe\InputCollectorInterface;
use Drupal\Core\Recipe\Recipe;
@@ -14,6 +15,7 @@
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\FunctionalTests\Core\Recipe\RecipeTestTrait;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\NodeType;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Style\StyleInterface;
use Symfony\Component\Validator\Exception\ValidationFailedException;
@@ -229,4 +231,45 @@ public function testLiterals(): void {
    $this->assertSame('int is 1234, bool is  and float is 3.141', $config->get('slogan'));
  }

  /**
   * Tests using input values in entity IDs for config actions.
   */
  public function testInputInConfigEntityIds(): void {
    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('node'));

    $collector = new class () implements InputCollectorInterface {

      /**
       * {@inheritdoc}
       */
      public function collectValue(string $name, DataDefinitionInterface $definition, mixed $default_value): mixed {
        return $default_value;
      }

    };
    $recipe = Recipe::createFromDirectory('core/tests/fixtures/recipes/input_test');
    $recipe->input->collectAll($collector);
    RecipeRunner::processRecipe($recipe);
    $this->assertInstanceOf(NodeType::class, NodeType::load('test'));

    // Using an input placeholder in a non-identifying part of the config entity
    // ID should cause an exception.
    $recipe = $this->createRecipe([
      'name' => 'Invalid use of an input in config entity ID',
      'config' => [
        'actions' => [
          'node.${anything}.test' => [
            'createIfNotExists' => [
              'id' => 'test',
            ],
          ],
        ],
      ],
    ]);
    $recipe->input->collectAll($collector);
    $this->expectException(ConfigActionException::class);
    $this->expectExceptionMessage("The entity type for the config name 'node.\${anything}.test' could not be identified.");
    RecipeRunner::processRecipe($recipe);
  }

}
+11 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ recipes:
  # Depend on another recipe in order to prove that we can collect input
  # from recipes that depend on other recipes.
  - no_extensions
install:
  - node
input:
  owner:
    data_type: string
@@ -27,8 +29,17 @@ input:
    default:
      source: value
      value: false
  node_type:
    data_type: string
    description: 'The ID of a node type to create'
    default:
      source: value
      value: 'test'
config:
  actions:
    node.type.${node_type}:
      createIfNotExists:
        name: Test Content Type
    system.site:
      simpleConfigUpdate:
        name: "${owner}'s Turf"