BreadcrumbManager.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. namespace Drupal\Core\Breadcrumb;
  3. use Drupal\Core\Extension\ModuleHandlerInterface;
  4. use Drupal\Core\Routing\RouteMatchInterface;
  5. /**
  6. * Provides a breadcrumb manager.
  7. *
  8. * Can be assigned any number of BreadcrumbBuilderInterface objects by calling
  9. * the addBuilder() method. When build() is called it iterates over the objects
  10. * in priority order and uses the first one that returns TRUE from
  11. * BreadcrumbBuilderInterface::applies() to build the breadcrumbs.
  12. *
  13. * @see \Drupal\Core\DependencyInjection\Compiler\RegisterBreadcrumbBuilderPass
  14. */
  15. class BreadcrumbManager implements ChainBreadcrumbBuilderInterface {
  16. /**
  17. * The module handler to invoke the alter hook.
  18. *
  19. * @var \Drupal\Core\Extension\ModuleHandlerInterface
  20. */
  21. protected $moduleHandler;
  22. /**
  23. * Holds arrays of breadcrumb builders, keyed by priority.
  24. *
  25. * @var array
  26. */
  27. protected $builders = [];
  28. /**
  29. * Holds the array of breadcrumb builders sorted by priority.
  30. *
  31. * Set to NULL if the array needs to be re-calculated.
  32. *
  33. * @var \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface[]|null
  34. */
  35. protected $sortedBuilders;
  36. /**
  37. * Constructs a \Drupal\Core\Breadcrumb\BreadcrumbManager object.
  38. *
  39. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
  40. * The module handler.
  41. */
  42. public function __construct(ModuleHandlerInterface $module_handler) {
  43. $this->moduleHandler = $module_handler;
  44. }
  45. /**
  46. * {@inheritdoc}
  47. */
  48. public function addBuilder(BreadcrumbBuilderInterface $builder, $priority) {
  49. $this->builders[$priority][] = $builder;
  50. // Force the builders to be re-sorted.
  51. $this->sortedBuilders = NULL;
  52. }
  53. /**
  54. * {@inheritdoc}
  55. */
  56. public function applies(RouteMatchInterface $route_match) {
  57. return TRUE;
  58. }
  59. /**
  60. * {@inheritdoc}
  61. */
  62. public function build(RouteMatchInterface $route_match) {
  63. $breadcrumb = new Breadcrumb();
  64. $context = ['builder' => NULL];
  65. // Call the build method of registered breadcrumb builders,
  66. // until one of them returns an array.
  67. foreach ($this->getSortedBuilders() as $builder) {
  68. if (!$builder->applies($route_match)) {
  69. // The builder does not apply, so we continue with the other builders.
  70. continue;
  71. }
  72. $breadcrumb = $builder->build($route_match);
  73. if ($breadcrumb instanceof Breadcrumb) {
  74. $context['builder'] = $builder;
  75. break;
  76. }
  77. else {
  78. throw new \UnexpectedValueException('Invalid breadcrumb returned by ' . get_class($builder) . '::build().');
  79. }
  80. }
  81. // Allow modules to alter the breadcrumb.
  82. $this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context);
  83. return $breadcrumb;
  84. }
  85. /**
  86. * Returns the sorted array of breadcrumb builders.
  87. *
  88. * @return \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface[]
  89. * An array of breadcrumb builder objects.
  90. */
  91. protected function getSortedBuilders() {
  92. if (!isset($this->sortedBuilders)) {
  93. // Sort the builders according to priority.
  94. krsort($this->builders);
  95. // Merge nested builders from $this->builders into $this->sortedBuilders.
  96. $this->sortedBuilders = [];
  97. foreach ($this->builders as $builders) {
  98. $this->sortedBuilders = array_merge($this->sortedBuilders, $builders);
  99. }
  100. }
  101. return $this->sortedBuilders;
  102. }
  103. }