From 7a2865154f202dc1f15e59e5d1ebb8931076ecc7 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Mon, 26 Feb 2024 13:53:19 +0000
Subject: [PATCH] Issue #3422398 by Wim Leers, phenaproxima: Allow specifying a
 prefix for ConfigExistsConstraint, to enable using it for references to
 config entities

---
 .../Validation/Constraint/ConfigExistsConstraint.php  | 11 +++++++++++
 .../Constraint/ConfigExistsConstraintValidator.php    |  6 ++++--
 .../Config/ConfigExistsConstraintValidatorTest.php    | 11 +++++++----
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php
index 006cebd464d4..e0162936839d 100644
--- a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php
+++ b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraint.php
@@ -23,4 +23,15 @@ class ConfigExistsConstraint extends Constraint {
    */
   public string $message = "The '@name' config does not exist.";
 
+  /**
+   * Optional prefix, to be specified when this contains a config entity ID.
+   *
+   * Every config entity type can have multiple instances, all with unique IDs
+   * but the same config prefix. When config refers to a config entity,
+   * typically only the ID is stored, not the prefix.
+   *
+   * @var string
+   */
+  public string $prefix = '';
+
 }
diff --git a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraintValidator.php b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraintValidator.php
index 83067c2c1b59..0f60e76b9bc7 100644
--- a/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraintValidator.php
+++ b/core/lib/Drupal/Core/Config/Plugin/Validation/Constraint/ConfigExistsConstraintValidator.php
@@ -43,13 +43,15 @@ public static function create(ContainerInterface $container) {
    * {@inheritdoc}
    */
   public function validate(mixed $name, Constraint $constraint) {
+    assert($constraint instanceof ConfigExistsConstraint);
+
     // This constraint may be used to validate nullable (optional) values.
     if ($name === NULL) {
       return;
     }
 
-    if (!in_array($name, $this->configFactory->listAll(), TRUE)) {
-      $this->context->addViolation($constraint->message, ['@name' => $name]);
+    if (!in_array($constraint->prefix . $name, $this->configFactory->listAll($constraint->prefix), TRUE)) {
+      $this->context->addViolation($constraint->message, ['@name' => $constraint->prefix . $name]);
     }
   }
 
diff --git a/core/tests/Drupal/KernelTests/Core/Config/ConfigExistsConstraintValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Config/ConfigExistsConstraintValidatorTest.php
index bb94ae83d795..67fd57a96d50 100644
--- a/core/tests/Drupal/KernelTests/Core/Config/ConfigExistsConstraintValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Config/ConfigExistsConstraintValidatorTest.php
@@ -23,20 +23,23 @@ class ConfigExistsConstraintValidatorTest extends KernelTestBase {
 
   /**
    * Tests the ConfigExists constraint validator.
+   *
+   * @testWith [{}, "system.site", "system.site"]
+   *           [{"prefix": "system."}, "site", "system.site"]
    */
-  public function testValidation(): void {
+  public function testValidation(array $constraint_options, string $value, string $expected_config_name): void {
     // Create a data definition that specifies the value must be a string with
     // the name of an existing piece of config.
     $definition = DataDefinition::create('string')
-      ->addConstraint('ConfigExists');
+      ->addConstraint('ConfigExists', $constraint_options);
 
     /** @var \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data */
     $typed_data = $this->container->get('typed_data_manager');
-    $data = $typed_data->create($definition, 'system.site');
+    $data = $typed_data->create($definition, $value);
 
     $violations = $data->validate();
     $this->assertCount(1, $violations);
-    $this->assertSame("The 'system.site' config does not exist.", (string) $violations->get(0)->getMessage());
+    $this->assertSame("The '$expected_config_name' config does not exist.", (string) $violations->get(0)->getMessage());
 
     $this->installConfig('system');
     $this->assertCount(0, $data->validate());
-- 
GitLab