|
25 | 25 | use Symfony\Component\HttpFoundation\Request;
|
26 | 26 | use Symfony\Component\HttpFoundation\Response;
|
27 | 27 | use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
| 28 | +use Symfony\Component\HttpKernel\Bundle\BundleDependenciesInterface; |
28 | 29 | use Symfony\Component\HttpKernel\Config\EnvParametersResource;
|
29 | 30 | use Symfony\Component\HttpKernel\Config\FileLocator;
|
30 | 31 | use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
|
@@ -459,7 +460,7 @@ protected function initializeBundles()
|
459 | 460 | $topMostBundles = array();
|
460 | 461 | $directChildren = array();
|
461 | 462 |
|
462 |
| - foreach ($this->registerBundles() as $bundle) { |
| 463 | + foreach ($this->orderedRegisteredBundlesAndDependencies() as $bundle) { |
463 | 464 | $name = $bundle->getName();
|
464 | 465 | if (isset($this->bundles[$name])) {
|
465 | 466 | throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name));
|
@@ -505,6 +506,89 @@ protected function initializeBundles()
|
505 | 506 | }
|
506 | 507 | }
|
507 | 508 |
|
| 509 | + /** |
| 510 | + * Returns an array of bundles to register, with dependencies, ordered |
| 511 | + * |
| 512 | + * @return \Symfony\Component\HttpKernel\Bundle\BundleInterface[] An array of bundle instances. |
| 513 | + */ |
| 514 | + protected function orderedRegisteredBundlesAndDependencies() |
| 515 | + { |
| 516 | + $bundles = $this->registerBundles(); |
| 517 | + $topMostBundles = $topMostBundlesMap = array(); |
| 518 | + $hasDependencies = false; |
| 519 | + |
| 520 | + // Build up bundles as a hash with FQN for basis to rebuild again in correct order given dependencies |
| 521 | + foreach ($bundles as $bundle) { |
| 522 | + $topMostBundles[] = $bundleFQN = get_class($bundle); |
| 523 | + $topMostBundlesMap[$bundleFQN] = $bundle; |
| 524 | + |
| 525 | + if ($bundle instanceof BundleDependenciesInterface) { |
| 526 | + $hasDependencies = true; |
| 527 | + } |
| 528 | + } |
| 529 | + |
| 530 | + if (!$hasDependencies) { |
| 531 | + return $bundles; |
| 532 | + } |
| 533 | + |
| 534 | + // Rebuild bundles order with dependencies recursively |
| 535 | + $bundles = array(); |
| 536 | + $this->appendDependenciesRecursively( |
| 537 | + $topMostBundles, |
| 538 | + $bundles, |
| 539 | + $topMostBundlesMap, |
| 540 | + get_class($this) |
| 541 | + ); |
| 542 | + |
| 543 | + return $bundles; |
| 544 | + } |
| 545 | + |
| 546 | + /** |
| 547 | + * Append dependencies of bundles recursively |
| 548 | + * |
| 549 | + * Accepted arguments are as documented below where `string` implies a string with class FQN(Fully Qualified Name), |
| 550 | + * this string must be in exactly same format as returned by get_class() and PHP 5.5's CLASS constant. |
| 551 | + * Example of FQN string: "Symfony\Component\HttpKernel\Bundle\BundleInterface" |
| 552 | + * |
| 553 | + * @param string[] $directChildren Dependencies to apply |
| 554 | + * @param \Symfony\Component\HttpKernel\Bundle\BundleInterface[<string>] $bundles Ordered bundles to append dependencies to |
| 555 | + * @param \Symfony\Component\HttpKernel\Bundle\BundleInterface[<string>] $topMostBundlesMap Loaded Bundles from registerRootBundles() |
| 556 | + * @param string $parent For use in exception message if a dependency can not be loaded. |
| 557 | + * |
| 558 | + * @throws \Exception |
| 559 | + */ |
| 560 | + protected function appendDependenciesRecursively(array $directChildren, array &$bundles, array $topMostBundlesMap, $parent) |
| 561 | + { |
| 562 | + while (!empty($directChildren)) { |
| 563 | + $dependencyFQN = array_shift($directChildren); |
| 564 | + if (isset($bundles[$dependencyFQN])) { |
| 565 | + continue; |
| 566 | + } |
| 567 | + |
| 568 | + // If already loaded root bundle, use that to not re instantiate |
| 569 | + if (isset($topMostBundlesMap[$dependencyFQN])) { |
| 570 | + $dependency = $topMostBundlesMap[$dependencyFQN]; |
| 571 | + } else { |
| 572 | + if (!class_exists($dependencyFQN)) { |
| 573 | + throw new \RuntimeException(sprintf("Could not find Bundle '%s', set as dependency by '%s'", $dependencyFQN, $parent)); |
| 574 | + } |
| 575 | + $dependency = new $dependencyFQN(); |
| 576 | + } |
| 577 | + |
| 578 | + // Append dependencies of the dependency before we append dependency itself |
| 579 | + if ($dependency instanceof BundleDependenciesInterface) { |
| 580 | + $this->appendDependenciesRecursively( |
| 581 | + $dependency->getBundleDependencies(), |
| 582 | + $bundles, |
| 583 | + $topMostBundlesMap, |
| 584 | + $dependencyFQN |
| 585 | + ); |
| 586 | + } |
| 587 | + |
| 588 | + $bundles[$dependencyFQN] = $dependency; |
| 589 | + } |
| 590 | + } |
| 591 | + |
508 | 592 | /**
|
509 | 593 | * Gets the container class.
|
510 | 594 | *
|
|
0 commit comments