From 9cd7babdc7e3322f86e11aba34c547967d82c60d Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Mon, 1 Jul 2024 16:06:46 +0100
Subject: [PATCH] Issue #3455113 by b_sharpe, ankitv18, alexpott, pooja_sharma,
 phenaproxima, thejimbirch: Rename ensure_exists to createIfNotExists, and
 camel-case simpleConfigUpdate for consistency

---
 .../Config/Action/ConfigActionManager.php     | 40 +++++++++++++++++++
 .../Deriver/EntityCreateDeriver.php           |  4 +-
 .../ConfigAction/SimpleConfigUpdate.php       |  2 +-
 core/recipes/administrator_role/recipe.yml    |  2 +-
 core/recipes/content_editor_role/recipe.yml   |  2 +-
 .../core_recommended_admin_theme/recipe.yml   |  2 +-
 .../recipe.yml                                |  2 +-
 core/recipes/example/recipe.yml               |  2 +-
 core/recipes/feedback_contact_form/recipe.yml |  2 +-
 core/recipes/standard/recipe.yml              |  6 +--
 .../Core/Config/Action/ConfigActionTest.php   | 16 ++++----
 .../Recipe/ConfigActionValidationTest.php     |  4 +-
 .../Core/Recipe/RecipeRunnerTest.php          | 23 ++++++++++-
 .../Core/Recipe/RecipeValidationTest.php      |  2 +-
 .../Core/Recipe/WildcardConfigActionsTest.php |  2 +-
 .../recipes/config_actions/recipe.yml         |  4 +-
 .../direct_dependency/recipe.yml              |  2 +-
 .../recipe.yml                                |  2 +-
 .../recipe.yml                                |  2 +-
 .../config_rollback_exception/recipe.yml      |  2 +-
 20 files changed, 92 insertions(+), 31 deletions(-)

diff --git a/core/lib/Drupal/Core/Config/Action/ConfigActionManager.php b/core/lib/Drupal/Core/Config/Action/ConfigActionManager.php
index cb030d6ba333..0bd38dd26d54 100644
--- a/core/lib/Drupal/Core/Config/Action/ConfigActionManager.php
+++ b/core/lib/Drupal/Core/Config/Action/ConfigActionManager.php
@@ -53,6 +53,22 @@
  */
 class ConfigActionManager extends DefaultPluginManager {
 
+  /**
+   * Information about all deprecated plugin IDs.
+   *
+   * @var string[]
+   */
+  private static array $deprecatedPluginIds = [
+    'entity_create:ensure_exists' => [
+      'replacement' => 'entity_create:createIfNotExists',
+      'message' => 'The plugin ID "entity_create:ensure_exists" is deprecated in drupal:10.3.1 and will be removed in drupal:12.0.0. Use "entity_create:createIfNotExists" instead. See https://www.drupal.org/node/3458273.',
+    ],
+    'simple_config_update' => [
+      'replacement' => 'simpleConfigUpdate',
+      'message' => 'The plugin ID "simple_config_update" is deprecated in drupal:10.3.1 and will be removed in drupal:12.0.0. Use "simpleConfigUpdate" instead. See https://www.drupal.org/node/3458273.',
+    ],
+  ];
+
   /**
    * Constructs a new \Drupal\Core\Config\Action\ConfigActionManager object.
    *
@@ -218,4 +234,28 @@ protected function getShorthandActionIdsForEntityType(string $entityType): array
     return $map;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function alterDefinitions(&$definitions): void {
+    // Adds backwards compatibility for plugins that have been renamed.
+    foreach (self::$deprecatedPluginIds as $legacy => $new_plugin_id) {
+      $definitions[$legacy] = $definitions[$new_plugin_id['replacement']];
+    }
+    parent::alterDefinitions($definitions);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createInstance($plugin_id, array $configuration = []) {
+    $instance = parent::createInstance($plugin_id, $configuration);
+    // Trigger deprecation notices for renamed plugins.
+    if (array_key_exists($plugin_id, self::$deprecatedPluginIds)) {
+      // phpcs:ignore Drupal.Semantics.FunctionTriggerError
+      @trigger_error(self::$deprecatedPluginIds[$plugin_id]['message'], E_USER_DEPRECATED);
+    }
+    return $instance;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/Deriver/EntityCreateDeriver.php b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/Deriver/EntityCreateDeriver.php
index c5f73f243859..ba0eff50a35c 100644
--- a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/Deriver/EntityCreateDeriver.php
+++ b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/Deriver/EntityCreateDeriver.php
@@ -22,8 +22,8 @@ public function getDerivativeDefinitions($base_plugin_definition) {
     // These derivatives apply to all entity types.
     $base_plugin_definition['entity_types'] = ['*'];
 
-    $this->derivatives['ensure_exists'] = $base_plugin_definition + ['constructor_args' => ['exists' => Exists::ReturnEarlyIfExists]];
-    $this->derivatives['ensure_exists']['admin_label'] = $this->t('Ensure entity exists');
+    $this->derivatives['createIfNotExists'] = $base_plugin_definition + ['constructor_args' => ['exists' => Exists::ReturnEarlyIfExists]];
+    $this->derivatives['createIfNotExists']['admin_label'] = $this->t('Create entity if it does not exist');
 
     $this->derivatives['create'] = $base_plugin_definition + ['constructor_args' => ['exists' => Exists::ErrorIfExists]];
     $this->derivatives['create']['admin_label'] = $this->t('Entity create');
diff --git a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php
index d6485304cc0f..2e9064f3a3fc 100644
--- a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php
+++ b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php
@@ -17,7 +17,7 @@
  *   This API is experimental.
  */
 #[ConfigAction(
-  id: 'simple_config_update',
+  id: 'simpleConfigUpdate',
   admin_label: new TranslatableMarkup('Simple configuration update'),
 )]
 final class SimpleConfigUpdate implements ConfigActionPluginInterface, ContainerFactoryPluginInterface {
diff --git a/core/recipes/administrator_role/recipe.yml b/core/recipes/administrator_role/recipe.yml
index d64a3fbae612..5392d24bfedb 100644
--- a/core/recipes/administrator_role/recipe.yml
+++ b/core/recipes/administrator_role/recipe.yml
@@ -5,7 +5,7 @@ config:
   actions:
     user.role.administrator:
       # If this role already exists, then this action has no effect. If it doesn't exist, we'll create it with the following values.
-      ensure_exists:
+      createIfNotExists:
         id: administrator
         label: Administrator
         weight: 3
diff --git a/core/recipes/content_editor_role/recipe.yml b/core/recipes/content_editor_role/recipe.yml
index ec37b4e61e6d..947b930c277e 100644
--- a/core/recipes/content_editor_role/recipe.yml
+++ b/core/recipes/content_editor_role/recipe.yml
@@ -5,7 +5,7 @@ config:
   actions:
     user.role.content_editor:
       # If this role already exists, then this action has no effect. If it doesn't exist, we'll create it with the following values.
-      ensure_exists:
+      createIfNotExists:
         id: content_editor
         label: 'Content editor'
         weight: 2
diff --git a/core/recipes/core_recommended_admin_theme/recipe.yml b/core/recipes/core_recommended_admin_theme/recipe.yml
index 5d60e2f5c9bf..cea2f383fbfc 100644
--- a/core/recipes/core_recommended_admin_theme/recipe.yml
+++ b/core/recipes/core_recommended_admin_theme/recipe.yml
@@ -20,5 +20,5 @@ config:
       - block.block.claro_secondary_local_tasks
   actions:
     system.theme:
-      simple_config_update:
+      simpleConfigUpdate:
         admin: claro
diff --git a/core/recipes/core_recommended_front_end_theme/recipe.yml b/core/recipes/core_recommended_front_end_theme/recipe.yml
index cdfb36b369ee..643046e68ad6 100644
--- a/core/recipes/core_recommended_front_end_theme/recipe.yml
+++ b/core/recipes/core_recommended_front_end_theme/recipe.yml
@@ -25,5 +25,5 @@ config:
       - core.date_format.olivero_medium
   actions:
     system.theme:
-      simple_config_update:
+      simpleConfigUpdate:
         default: olivero
diff --git a/core/recipes/example/recipe.yml b/core/recipes/example/recipe.yml
index e60573749e60..64cd0b4f584b 100644
--- a/core/recipes/example/recipe.yml
+++ b/core/recipes/example/recipe.yml
@@ -36,7 +36,7 @@ config:
   # mapped to the \Drupal\user\Entity\Role::grantPermission() method.
   actions:
     user.role.editor:
-      ensure_exists:
+      createIfNotExists:
         label: 'Editor'
       grantPermissions:
         - 'delete any article content'
diff --git a/core/recipes/feedback_contact_form/recipe.yml b/core/recipes/feedback_contact_form/recipe.yml
index c6368c6cfe56..8e6814c065ee 100644
--- a/core/recipes/feedback_contact_form/recipe.yml
+++ b/core/recipes/feedback_contact_form/recipe.yml
@@ -11,7 +11,7 @@ config:
       - system.menu.footer
   actions:
     core.menu.static_menu_link_overrides:
-      simple_config_update:
+      simpleConfigUpdate:
         definitions.contact__site_page:
           menu_name: footer
           parent: ''
diff --git a/core/recipes/standard/recipe.yml b/core/recipes/standard/recipe.yml
index bd331c6eb82a..7df5437c0e1c 100644
--- a/core/recipes/standard/recipe.yml
+++ b/core/recipes/standard/recipe.yml
@@ -64,10 +64,10 @@ config:
       - views.view.who_s_online
   actions:
     node.settings:
-      simple_config_update:
+      simpleConfigUpdate:
         use_admin_theme: true
     system.site:
-      simple_config_update:
+      simpleConfigUpdate:
         page.front: /node
     user.role.anonymous:
       grantPermission: 'access content'
@@ -96,7 +96,7 @@ config:
         - 'delete own %bundle content'
         - 'edit own %bundle content'
     user.settings:
-      simple_config_update:
+      simpleConfigUpdate:
         verify_mail: true
         register: admin_only
         cancel_method: user_cancel_block
diff --git a/core/tests/Drupal/KernelTests/Core/Config/Action/ConfigActionTest.php b/core/tests/Drupal/KernelTests/Core/Config/Action/ConfigActionTest.php
index ec34c1036b73..1cb14673abea 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/Action/ConfigActionTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/Action/ConfigActionTest.php
@@ -33,15 +33,15 @@ public function testEntityCreate(): void {
     $this->assertCount(0, \Drupal::entityTypeManager()->getStorage('config_test')->loadMultiple(), 'There are no config_test entities');
     /** @var \Drupal\Core\Config\Action\ConfigActionManager $manager */
     $manager = $this->container->get('plugin.manager.config_action');
-    $manager->applyAction('entity_create:ensure_exists', 'config_test.dynamic.action_test', ['label' => 'Action test']);
+    $manager->applyAction('entity_create:createIfNotExists', 'config_test.dynamic.action_test', ['label' => 'Action test']);
     /** @var \Drupal\config_test\Entity\ConfigTest[] $config_test_entities */
     $config_test_entities = \Drupal::entityTypeManager()->getStorage('config_test')->loadMultiple();
     $this->assertCount(1, \Drupal::entityTypeManager()->getStorage('config_test')->loadMultiple(), 'There is 1 config_test entity');
     $this->assertSame('Action test', $config_test_entities['action_test']->label());
     $this->assertTrue(Uuid::isValid((string) $config_test_entities['action_test']->uuid()), 'Config entity assigned a valid UUID');
 
-    // Calling ensure exists action again will not error.
-    $manager->applyAction('entity_create:ensure_exists', 'config_test.dynamic.action_test', ['label' => 'Action test']);
+    // Calling createIfNotExists action again will not error.
+    $manager->applyAction('entity_create:createIfNotExists', 'config_test.dynamic.action_test', ['label' => 'Action test']);
 
     try {
       $manager->applyAction('entity_create:create', 'config_test.dynamic.action_test', ['label' => 'Action test']);
@@ -244,11 +244,11 @@ public function testSimpleConfigUpdate(): void {
     /** @var \Drupal\Core\Config\Action\ConfigActionManager $manager */
     $manager = $this->container->get('plugin.manager.config_action');
     // Call the simple config update action.
-    $manager->applyAction('simple_config_update', 'config_test.system', ['foo' => 'Yay!']);
+    $manager->applyAction('simpleConfigUpdate', 'config_test.system', ['foo' => 'Yay!']);
     $this->assertSame('Yay!', $this->config('config_test.system')->get('foo'));
 
     try {
-      $manager->applyAction('simple_config_update', 'config_test.system', 'Test');
+      $manager->applyAction('simpleConfigUpdate', 'config_test.system', 'Test');
       $this->fail('Expected exception not thrown');
     }
     catch (ConfigActionException $e) {
@@ -257,7 +257,7 @@ public function testSimpleConfigUpdate(): void {
 
     $this->config('config_test.system')->delete();
     try {
-      $manager->applyAction('simple_config_update', 'config_test.system', ['foo' => 'Yay!']);
+      $manager->applyAction('simpleConfigUpdate', 'config_test.system', ['foo' => 'Yay!']);
       $this->fail('Expected exception not thrown');
     }
     catch (ConfigActionException $e) {
@@ -273,7 +273,7 @@ public function testShorthandActionIds(): void {
     $this->assertCount(0, $storage->loadMultiple(), 'There are no config_test entities');
     /** @var \Drupal\Core\Config\Action\ConfigActionManager $manager */
     $manager = $this->container->get('plugin.manager.config_action');
-    $manager->applyAction('ensure_exists', 'config_test.dynamic.action_test', ['label' => 'Action test', 'protected_property' => '']);
+    $manager->applyAction('createIfNotExists', 'config_test.dynamic.action_test', ['label' => 'Action test', 'protected_property' => '']);
     /** @var \Drupal\config_test\Entity\ConfigTest[] $config_test_entities */
     $config_test_entities = $storage->loadMultiple();
     $this->assertCount(1, $config_test_entities, 'There is 1 config_test entity');
@@ -299,7 +299,7 @@ public function testDuplicateShorthandActionIds(): void {
     $manager = $this->container->get('plugin.manager.config_action');
     $this->expectException(DuplicateConfigActionIdException::class);
     $this->expectExceptionMessage("The plugins 'entity_method:config_test.dynamic:setProtectedProperty' and 'config_action_duplicate_test:config_test.dynamic:setProtectedProperty' both resolve to the same shorthand action ID for the 'config_test' entity type");
-    $manager->applyAction('ensure_exists', 'config_test.dynamic.action_test', ['label' => 'Action test', 'protected_property' => '']);
+    $manager->applyAction('createIfNotExists', 'config_test.dynamic.action_test', ['label' => 'Action test', 'protected_property' => '']);
   }
 
   /**
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php
index eef3ba5f8a60..e5df2b824b19 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php
@@ -77,7 +77,7 @@ public function testConfigActionsAreValidated(string $entity_type_id): void {
 config:
   actions:
     $config_name:
-      simple_config_update:
+      simpleConfigUpdate:
         $label_key: ''
 YAML;
 
@@ -118,7 +118,7 @@ public function testConfigActionMissingDependency(): void {
 config:
   actions:
     random.config:
-      simple_config_update:
+      simpleConfigUpdate:
         label: ''
 YAML;
 
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/RecipeRunnerTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/RecipeRunnerTest.php
index 0af066b626cd..64d94653c138 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/RecipeRunnerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/RecipeRunnerTest.php
@@ -208,7 +208,7 @@ public function testInvalidConfigAction() :void {
 config:
   actions:
     config_test.dynamic.recipe:
-      ensure_exists:
+      createIfNotExists:
         label: 'Created by recipe'
       setBody: 'Description set by recipe'
 YAML;
@@ -219,6 +219,27 @@ public function testInvalidConfigAction() :void {
     RecipeRunner::processRecipe($recipe);
   }
 
+  /**
+   * Tests that renamed plugins are marked as deprecated.
+   *
+   * @group legacy
+   */
+  public function testRenamedConfigActions(): void {
+    $recipe_data = <<<YAML
+name: Renamed config action
+install:
+  - config_test
+config:
+  actions:
+    config_test.dynamic.recipe:
+      ensure_exists:
+        label: 'Created by recipe'
+YAML;
+    $recipe = $this->createRecipe($recipe_data);
+    $this->expectDeprecation('The plugin ID "entity_create:ensure_exists" is deprecated in drupal:10.3.1 and will be removed in drupal:12.0.0. Use "entity_create:createIfNotExists" instead. See https://www.drupal.org/node/3458273.');
+    RecipeRunner::processRecipe($recipe);
+  }
+
   public function testRecipesAreDisambiguatedByPath(): void {
     $recipe_data = <<<YAML
 name: 'Recipe include'
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/RecipeValidationTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/RecipeValidationTest.php
index 20551fb972ff..2050992cafad 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/RecipeValidationTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/RecipeValidationTest.php
@@ -264,7 +264,7 @@ public static function providerRecipeValidation(): iterable {
 config:
   actions:
     config_test.dynamic.recipe:
-      ensure_exists:
+      createIfNotExists:
         label: 'Created by recipe'
       setProtectedProperty: 'Set by recipe'
 YAML,
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/WildcardConfigActionsTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/WildcardConfigActionsTest.php
index 29b1a7e784e6..0b9600aa6af6 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/WildcardConfigActionsTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/WildcardConfigActionsTest.php
@@ -122,7 +122,7 @@ public function testInvalidExpression(string $expression, string $expected_excep
 config:
   actions:
     $expression:
-      simple_config_update:
+      simpleConfigUpdate:
         label: 'Changed by config action'
 YAML;
     $recipe = $this->createRecipe($contents);
diff --git a/core/tests/fixtures/recipes/config_actions/recipe.yml b/core/tests/fixtures/recipes/config_actions/recipe.yml
index 4e16eeb67b73..875ef5ace374 100644
--- a/core/tests/fixtures/recipes/config_actions/recipe.yml
+++ b/core/tests/fixtures/recipes/config_actions/recipe.yml
@@ -5,9 +5,9 @@ install:
 config:
   actions:
     config_test.dynamic.recipe:
-      ensure_exists:
+      createIfNotExists:
         label: 'Created by recipe'
       setProtectedProperty: 'Set by recipe'
     config_test.system:
-      simple_config_update:
+      simpleConfigUpdate:
         foo: 'not bar'
diff --git a/core/tests/fixtures/recipes/config_actions_dependency_validation/direct_dependency/recipe.yml b/core/tests/fixtures/recipes/config_actions_dependency_validation/direct_dependency/recipe.yml
index 369e09357e7c..1a727dd95be7 100644
--- a/core/tests/fixtures/recipes/config_actions_dependency_validation/direct_dependency/recipe.yml
+++ b/core/tests/fixtures/recipes/config_actions_dependency_validation/direct_dependency/recipe.yml
@@ -5,5 +5,5 @@ install:
 config:
   actions:
     node.settings:
-      simple_config_update:
+      simpleConfigUpdate:
         use_admin_theme: true
diff --git a/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_one_level_down/recipe.yml b/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_one_level_down/recipe.yml
index f6ebd037e865..616ac4810cc8 100644
--- a/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_one_level_down/recipe.yml
+++ b/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_one_level_down/recipe.yml
@@ -5,5 +5,5 @@ recipes:
 config:
   actions:
     node.settings:
-      simple_config_update:
+      simpleConfigUpdate:
         use_admin_theme: true
diff --git a/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_two_levels_down/recipe.yml b/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_two_levels_down/recipe.yml
index ac2e9bdef7cd..0b31dd129fdb 100644
--- a/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_two_levels_down/recipe.yml
+++ b/core/tests/fixtures/recipes/config_actions_dependency_validation/indirect_dependency_two_levels_down/recipe.yml
@@ -5,5 +5,5 @@ recipes:
 config:
   actions:
     node.settings:
-      simple_config_update:
+      simpleConfigUpdate:
         use_admin_theme: true
diff --git a/core/tests/fixtures/recipes/config_rollback_exception/recipe.yml b/core/tests/fixtures/recipes/config_rollback_exception/recipe.yml
index 2bf0db3433cb..325d1415fa18 100644
--- a/core/tests/fixtures/recipes/config_rollback_exception/recipe.yml
+++ b/core/tests/fixtures/recipes/config_rollback_exception/recipe.yml
@@ -15,5 +15,5 @@ config:
       # This will cause a validation error, which will trigger a rollback.
       # The rollback should fail, since the Media module can't be uninstalled
       # now that the plain_text format is using one of its filters.
-      simple_config_update:
+      simpleConfigUpdate:
         non_existent_key: whatever!
-- 
GitLab