From e29a7d8eb6aa23ddcfd98eb4ee8015f0c1f181a7 Mon Sep 17 00:00:00 2001
From: Bram Goffings <bramgoffings@gmail.com>
Date: Mon, 13 Aug 2012 23:28:42 +0200
Subject: [PATCH] multiple parenting bundles

---
 core/lib/Drupal/Core/DrupalKernel.php | 84 ++++++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 2 deletions(-)

diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 869d4ee..364596e 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -8,10 +8,11 @@
 namespace Drupal\Core;
 
 use Drupal\Core\CoreBundle;
-use Symfony\Component\HttpKernel\Kernel;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Kernel;
 use Symfony\Component\Config\Loader\LoaderInterface;
 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
+use Exception;
 
 /**
  * The DrupalKernel class is the core of Drupal itself.
@@ -81,7 +82,10 @@ class DrupalKernel extends Kernel {
     if ($bootstrap_container = drupal_container()) {
       $container->merge($bootstrap_container);
     }
-    foreach ($this->bundles as $bundle) {
+    // Build the container in the expected order
+    foreach($this->bundleMap as $bundleArray) {
+      // The needed bundle sits in the last position of the array
+      $bundle = array_pop($bundleArray);
       $bundle->build($container);
     }
 
@@ -112,4 +116,80 @@ class DrupalKernel extends Kernel {
    */
   public function registerContainerConfiguration(LoaderInterface $loader) {
   }
+
+  /**
+   * Overrides Symfony\Component\HttpKernel\Kernel::initializeBundles()
+   *
+   * @throws Exception
+   */
+  protected function initializeBundles()
+  {
+    // init bundles
+    $this->bundles = array();
+    $topMostBundles = array();
+    $directChildren = array();
+
+    foreach ($this->registerBundles() as $bundle) {
+      $name = $bundle->getName();
+      if (isset($this->bundles[$name])) {
+        throw new Exception(sprintf('Trying to register two bundles with the same name "%s"', $name));
+      }
+      $this->bundles[$name] = $bundle;
+
+      if ($parentName = $bundle->getParent()) {
+        if ($parentName == $name) {
+          throw new Exception(sprintf('Bundle "%s" can not extend itself.', $name));
+        }
+        $directChildren[$parentName][] = $name;
+      } else {
+        $topMostBundles[$name] = $bundle;
+      }
+    }
+
+    // look for orphans
+    if (count($diff = array_values(array_diff(array_keys($directChildren), array_keys($this->bundles))))) {
+      throw new Exception(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0]));
+    }
+
+    // inheritance
+    $this->bundleMap = array();
+    foreach ($topMostBundles as $name => $bundle) {
+      $bundleMap = array($bundle);
+      $hierarchy = array($name);
+
+      $this->buildInheritanceMap($directChildren, $name, $bundleMap, $hierarchy);
+
+      foreach ($hierarchy as $bundle) {
+        $this->bundleMap[$bundle] = $bundleMap;
+        array_pop($bundleMap);
+      }
+    }
+  }
+
+  /**
+   * Builds the inheritance mapping.
+   *
+   * @param $directChildren
+   *   A nested array containing the parent dependencies.
+   * @param $parent
+   *   The bundle we would like to build the bundleMap for.
+   * @param $bundleMap
+   *   Holds all the dependency information for each Bundle.
+   * @param $hierarchy
+   *   Holds the order of the bundles according to their dependencies.
+   */
+  private function buildInheritanceMap(&$directChildren, &$parent, &$bundleMap, &$hierarchy) {
+    if (isset($directChildren[$parent])) {
+      foreach ($directChildren[$parent] as $child) {
+        array_unshift($bundleMap, $this->bundles[$child]);
+        $hierarchy[] = $child;
+      }
+
+      // Go recursive deeper but only after the current children are added
+      foreach ($directChildren[$parent] as $child) {
+        $this->buildInheritanceMap($directChildren, $child, $bundleMap, $hierarchy);
+      }
+    }
+  }
+
 }
-- 
1.7.11.msysgit.1

