From 44c83898d5b9d219b4492ced351ca62e88166d99 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Tue, 3 Sep 2013 00:00:59 +0100
Subject: [PATCH] Issue #1972816 by yched | vijaycs85: Fixed Add support for
 %parent.%parent in config schema dynamic type names.

---
 .../Drupal/Core/Config/TypedConfigManager.php | 16 +++++-
 .../Drupal/config/Tests/ConfigSchemaTest.php  | 36 +++++++++++++
 .../config_test.someschema.with_parents.yml   | 12 +++++
 .../config/schema/config_test.schema.yml      | 54 +++++++++++++++++++
 4 files changed, 116 insertions(+), 2 deletions(-)
 create mode 100644 core/modules/config/tests/config_test/config/config_test.someschema.with_parents.yml

diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
index 896b08e07426..64735ad2ab29 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManager.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -85,7 +85,7 @@ public function create(array $definition, $value = NULL, $name = NULL, $parent =
       // Replace variable names in definition.
       $replace = is_array($value) ? $value : array();
       if (isset($parent)) {
-        $replace['%parent'] = $parent->getValue();
+        $replace['%parent'] = $parent;
       }
       if (isset($name)) {
         $replace['%key'] = $name;
@@ -268,7 +268,19 @@ protected function replaceVariable($value, $data) {
       }
       else {
         // Get nested value and continue processing.
-        $data = $data[$name];
+        if ($name == '%parent') {
+          // Switch replacement values with values from the parent.
+          $parent = $data['%parent'];
+          $data = $parent->getValue();
+          // The special %parent and %key values now need to point one level up.
+          if ($new_parent = $parent->getParent()) {
+            $data['%parent'] = $new_parent;
+            $data['%key'] = $new_parent->getName();
+          }
+        }
+        else {
+          $data = $data[$name];
+        }
       }
     }
   }
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
index 4a507d892d1c..e1ea9b7ad181 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
@@ -154,7 +154,43 @@ function testSchemaMapping() {
     $definition = config_typed()->getDefinition('config_test.someschema.somemodule.section_two.subsection');
     // The other file should have the same schema.
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_test.someschema.somemodule.section_two.subsection');
+  }
 
+  /**
+   * Tests metadata retrieval with several levels of %parent indirection.
+   */
+  function testSchemaMappingWithParents() {
+    $config_data = config_typed()->get('config_test.someschema.with_parents');
+
+    // Test fetching parent one level up.
+    $entry = $config_data->get('one_level');
+    $definition = $entry['testitem']->getDefinition();
+    $expected = array(
+      'type' => 'config_test.someschema.with_parents.key_1',
+      'label' => 'Test item nested one level',
+      'class' => '\Drupal\Core\TypedData\Plugin\DataType\String',
+    );
+    $this->assertEqual($definition, $expected);
+
+    // Test fetching parent two levels up.
+    $entry = $config_data->get('two_levels');
+    $definition = $entry['wrapper']['testitem']->getDefinition();
+    $expected = array(
+      'type' => 'config_test.someschema.with_parents.key_2',
+      'label' => 'Test item nested two levels',
+      'class' => '\Drupal\Core\TypedData\Plugin\DataType\String',
+    );
+    $this->assertEqual($definition, $expected);
+
+    // Test fetching parent three levels up.
+    $entry = $config_data->get('three_levels');
+    $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDefinition();
+    $expected = array(
+      'type' => 'config_test.someschema.with_parents.key_3',
+      'label' => 'Test item nested three levels',
+      'class' => '\Drupal\Core\TypedData\Plugin\DataType\String',
+    );
+    $this->assertEqual($definition, $expected);
   }
 
   /**
diff --git a/core/modules/config/tests/config_test/config/config_test.someschema.with_parents.yml b/core/modules/config/tests/config_test/config/config_test.someschema.with_parents.yml
new file mode 100644
index 000000000000..7f6870bcaeb2
--- /dev/null
+++ b/core/modules/config/tests/config_test/config/config_test.someschema.with_parents.yml
@@ -0,0 +1,12 @@
+one_level:
+  target_key: key_1
+  testitem: "text for entry_1"
+two_levels:
+  target_key: key_2
+  wrapper:
+    testitem: "text for entry_2"
+three_levels:
+  target_key: key_3
+  wrapper_1:
+    wrapper_2:
+      testitem: "text for entry_3"
diff --git a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
index d0791ee4d31a..b985aad089c1 100644
--- a/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
+++ b/core/modules/config/tests/config_test/config/schema/config_test.schema.yml
@@ -7,6 +7,60 @@ config_test.someschema:
     "testlist":
       label: "Test list"
 
+config_test.someschema.with_parents:
+  label: "Schema test data with parenting"
+  type: mapping
+  mapping:
+    one_level:
+      label: "Parenting one level up"
+      type: mapping
+      mapping:
+        target_key:
+          label: "Key used in parent relation"
+          type: string
+        testitem:
+          type: config_test.someschema.with_parents.[%parent.target_key]
+    two_levels:
+      label: "Parenting two levels up"
+      type: mapping
+      mapping:
+        target_key:
+          label: "Key used in parent relation"
+          type: string
+        wrapper:
+          label: "Wrapper"
+          type: mapping
+          mapping:
+            testitem:
+              type: config_test.someschema.with_parents.[%parent.%parent.target_key]
+    three_levels:
+      label: "Parenting three levels up"
+      type: mapping
+      mapping:
+        target_key:
+          label: "Key used in parent relation"
+          type: string
+        wrapper_1:
+          label: "Wrapper 1"
+          type: mapping
+          mapping:
+            wrapper_2:
+              label: "Wrapper 2"
+              type: mapping
+              mapping:
+                testitem:
+                  type: config_test.someschema.with_parents.[%parent.%parent.%parent.target_key]
+
+config_test.someschema.with_parents.key_1:
+  label: "Test item nested one level"
+  type: string
+config_test.someschema.with_parents.key_2:
+  label: "Test item nested two levels"
+  type: string
+config_test.someschema.with_parents.key_3:
+  label: "Test item nested three levels"
+  type: string
+
 config_test.someschema.somemodule.*.*:
   type: mapping
   label: 'Schema multiple filesytem marker test'
-- 
GitLab