diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php index 1fae4c6417d362700b1ebf7f2d0bc3d356e835db..cff4c544b156f0d07b197eb43f27ebc5371b9995 100644 --- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php +++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbBuilderInterface.php @@ -12,15 +12,27 @@ */ interface BreadcrumbBuilderInterface { + /** + * Whether this breadcrumb builder should be used to build the breadcrumb. + * + * @param array $attributes + * Attributes representing the current page. + * + * @return bool + * TRUE if this builder should be used or FALSE to let other builders + * decide. + */ + public function applies(array $attributes); + /** * Builds the breadcrumb. * * @param array $attributes * Attributes representing the current page. * - * @return array|null - * A render array for the breadcrumbs or NULL to let other builders decide. - * Returning empty array will suppress all breadcrumbs. + * @return array + * A render array for the breadcrumbs. Returning an empty array will + * suppress all breadcrumbs. */ public function build(array $attributes); diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php index 9e6f9b7ee90102ddf002ec0b7ae3772b39241cc4..a995317b64bf28463962635b12b9ddd92e141de3 100644 --- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php +++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php @@ -65,6 +65,13 @@ public function addBuilder(BreadcrumbBuilderInterface $builder, $priority) { $this->sortedBuilders = NULL; } + /** + * {@inheritdoc} + */ + public function applies(array $attributes) { + return TRUE; + } + /** * {@inheritdoc} */ @@ -74,12 +81,14 @@ public function build(array $attributes) { // Call the build method of registered breadcrumb builders, // until one of them returns an array. foreach ($this->getSortedBuilders() as $builder) { - $build = $builder->build($attributes); - if (!isset($build)) { - // The builder returned NULL, so we continue with the other builders. + if (!$builder->applies($attributes)) { + // The builder does not apply, so we continue with the other builders. continue; } - elseif (is_array($build)) { + + $build = $builder->build($attributes); + + if (is_array($build)) { // The builder returned an array of breadcrumb links. $breadcrumb = $build; $context['builder'] = $builder; diff --git a/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php b/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php index 3ad730fb12cadfa01c119341f868429124093b6b..6dd54ffe573b07e5502a59208299329ba7157989 100644 --- a/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php +++ b/core/modules/book/lib/Drupal/book/BookBreadcrumbBuilder.php @@ -55,34 +55,41 @@ public function __construct(EntityManagerInterface $entity_manager, AccessManage $this->account = $account; } + /** + * {@inheritdoc} + */ + public function applies(array $attributes) { + return !empty($attributes['node']) + && ($attributes['node'] instanceof NodeInterface) + && !empty($attributes['node']->book); + } + /** * {@inheritdoc} */ public function build(array $attributes) { - if (!empty($attributes['node']) && $attributes['node'] instanceof NodeInterface && !empty($attributes['node']->book)) { - $mlids = array(); - $links = array($this->l($this->t('Home'), '')); - $book = $attributes['node']->book; + $mlids = array(); + $links = array($this->l($this->t('Home'), '')); + $book = $attributes['node']->book; + $depth = 1; + // We skip the current node. + while (!empty($book['p' . ($depth + 1)])) { + $mlids[] = $book['p' . $depth]; + $depth++; + } + $menu_links = $this->menuLinkStorage->loadMultiple($mlids); + if (count($menu_links) > 0) { $depth = 1; - // We skip the current node. while (!empty($book['p' . ($depth + 1)])) { - $mlids[] = $book['p' . $depth]; - $depth++; - } - $menu_links = $this->menuLinkStorage->loadMultiple($mlids); - if (count($menu_links) > 0) { - $depth = 1; - while (!empty($book['p' . ($depth + 1)])) { - if (!empty($menu_links[$book['p' . $depth]]) && ($menu_link = $menu_links[$book['p' . $depth]])) { - if ($this->accessManager->checkNamedRoute($menu_link->route_name, $menu_link->route_parameters, $this->account)) { - $links[] = $this->l($menu_link->label(), $menu_link->route_name, $menu_link->route_parameters, $menu_link->options); - } + if (!empty($menu_links[$book['p' . $depth]]) && ($menu_link = $menu_links[$book['p' . $depth]])) { + if ($this->accessManager->checkNamedRoute($menu_link->route_name, $menu_link->route_parameters, $this->account)) { + $links[] = $this->l($menu_link->label(), $menu_link->route_name, $menu_link->route_parameters, $menu_link->options); } - $depth++; } + $depth++; } - return $links; } + return $links; } } diff --git a/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php b/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php index e7a4bb8198ec76997fc43d46f8444aea731373de..aa41c41599fa68f6d16b11269a68a814b1db3ca3 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php +++ b/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php @@ -33,23 +33,29 @@ public function __construct(EntityManagerInterface $entity_manager) { $this->entityManager = $entity_manager; } + /** + * {@inheritdoc} + */ + public function applies(array $attributes) { + return isset($attributes[RouteObjectInterface::ROUTE_NAME]) && $attributes[RouteObjectInterface::ROUTE_NAME] == 'comment.reply' + && isset($attributes['entity_type']) + && isset($attributes['entity_id']) + && isset($attributes['field_name']); + } + /** * {@inheritdoc} */ public function build(array $attributes) { - if (isset($attributes[RouteObjectInterface::ROUTE_NAME]) && $attributes[RouteObjectInterface::ROUTE_NAME] == 'comment.reply' - && isset($attributes['entity_type']) - && isset($attributes['entity_id']) - && isset($attributes['field_name']) - ) { - $breadcrumb[] = $this->l($this->t('Home'), ''); - $entity = $this->entityManager - ->getStorageController($attributes['entity_type']) - ->load($attributes['entity_id']); - $uri = $entity->uri(); - $breadcrumb[] = l($entity->label(), $uri['path'], $uri['options']); - return $breadcrumb; - } + $breadcrumb = array(); + + $breadcrumb[] = $this->l($this->t('Home'), ''); + $entity = $this->entityManager + ->getStorageController($attributes['entity_type']) + ->load($attributes['entity_id']); + $uri = $entity->uri(); + $breadcrumb[] = l($entity->label(), $uri['path'], $uri['options']); + return $breadcrumb; } } diff --git a/core/modules/forum/lib/Drupal/forum/ForumBreadcrumbBuilder.php b/core/modules/forum/lib/Drupal/forum/ForumBreadcrumbBuilder.php index e49f0930069057945481eacc4a8b8c386f9f6b4b..6128aa8db06aae70b96a742dbdd1b95caddd7387 100644 --- a/core/modules/forum/lib/Drupal/forum/ForumBreadcrumbBuilder.php +++ b/core/modules/forum/lib/Drupal/forum/ForumBreadcrumbBuilder.php @@ -55,20 +55,25 @@ public function __construct(EntityManagerInterface $entity_manager, ConfigFactor $this->forumManager = $forum_manager; } + /** + * {@inheritdoc} + */ + public function applies(array $attributes) { + return !empty($attributes[RouteObjectInterface::ROUTE_NAME]) + && (($attributes[RouteObjectInterface::ROUTE_NAME] == 'node.view' && isset($attributes['node']) && $this->forumManager->checkNodeType($attributes['node'])) + || ($attributes[RouteObjectInterface::ROUTE_NAME] == 'forum.page' && isset($attributes['taxonomy_term'])) + ); + } + /** * {@inheritdoc} */ public function build(array $attributes) { - if (!empty($attributes[RouteObjectInterface::ROUTE_NAME])) { - $route_name = $attributes[RouteObjectInterface::ROUTE_NAME]; - if ($route_name == 'node.view' && isset($attributes['node'])) { - if ($this->forumManager->checkNodeType($attributes['node'])) { - return $this->forumPostBreadcrumb($attributes['node']); - } - } - if ($route_name == 'forum.page' && isset($attributes['taxonomy_term'])) { - return $this->forumTermBreadcrumb($attributes['taxonomy_term']); - } + if ($attributes[RouteObjectInterface::ROUTE_NAME] == 'node.view') { + return $this->forumPostBreadcrumb($attributes['node']); + } + elseif ($attributes[RouteObjectInterface::ROUTE_NAME] == 'forum.page') { + return $this->forumTermBreadcrumb($attributes['taxonomy_term']); } } diff --git a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php index 1f592564e962867408113e120c85271fb717ea42..f185e48880f89d90bae573f7065c4431d512713c 100644 --- a/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php +++ b/core/modules/system/lib/Drupal/system/PathBasedBreadcrumbBuilder.php @@ -102,6 +102,13 @@ public function __construct(Request $request, EntityManagerInterface $entity_man $this->titleResolver = $title_resolver; } + /** + * {@inheritdoc} + */ + public function applies(array $attributes) { + return TRUE; + } + /** * {@inheritdoc} */ diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermBreadcrumbBuilder.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermBreadcrumbBuilder.php index 3a6e3e954bee0f48b57caedb1e6192bc86eba6d3..e886357d59769cac0c834f6d56379798a8971900 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermBreadcrumbBuilder.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermBreadcrumbBuilder.php @@ -15,24 +15,32 @@ */ class TermBreadcrumbBuilder extends BreadcrumbBuilderBase { + /** + * {@inheritdoc} + */ + public function applies(array $attributes) { + return !empty($attributes[RouteObjectInterface::ROUTE_NAME]) + && ($attributes[RouteObjectInterface::ROUTE_NAME] == 'taxonomy.term_page') + && ($attributes['taxonomy_term'] instanceof TermInterface); + } + /** * {@inheritdoc} */ public function build(array $attributes) { - if (!empty($attributes[RouteObjectInterface::ROUTE_NAME]) && $attributes[RouteObjectInterface::ROUTE_NAME] == 'taxonomy.term_page' && ($term = $attributes['taxonomy_term']) && $term instanceof TermInterface) { - // @todo This overrides any other possible breadcrumb and is a pure - // hard-coded presumption. Make this behavior configurable per - // vocabulary or term. - $breadcrumb = array(); - while ($parents = taxonomy_term_load_parents($term->id())) { - $term = array_shift($parents); - $breadcrumb[] = $this->l($term->label(), 'taxonomy.term_page', array('taxonomy_term' => $term->id())); - } - $breadcrumb[] = $this->l($this->t('Home'), ''); - $breadcrumb = array_reverse($breadcrumb); - - return $breadcrumb; + $term = $attributes['taxonomy_term']; + // @todo This overrides any other possible breadcrumb and is a pure + // hard-coded presumption. Make this behavior configurable per + // vocabulary or term. + $breadcrumb = array(); + while ($parents = taxonomy_term_load_parents($term->id())) { + $term = array_shift($parents); + $breadcrumb[] = $this->l($term->label(), 'taxonomy.term_page', array('taxonomy_term' => $term->id())); } + $breadcrumb[] = $this->l($this->t('Home'), ''); + $breadcrumb = array_reverse($breadcrumb); + + return $breadcrumb; } } diff --git a/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php b/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php index f3ac82abe299479db98fc57ef738900c663a97a5..49dcad88451058c46594879fc7fc574d189a5a95 100644 --- a/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Breadcrumb/BreadcrumbManagerTest.php @@ -70,6 +70,10 @@ public function testBuildWithSingleBuilder() { $attributes = array('key' => 'value'); + $builder->expects($this->once()) + ->method('applies') + ->will($this->returnValue(TRUE)); + $builder->expects($this->once()) ->method('build') ->will($this->returnValue($breadcrumb)); @@ -89,11 +93,16 @@ public function testBuildWithSingleBuilder() { */ public function testBuildWithMultipleApplyingBuilders() { $builder1 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); + $builder1->expects($this->never()) + ->method('applies'); $builder1->expects($this->never()) ->method('build'); $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $breadcrumb2 = array('Test2'); + $builder2->expects($this->once()) + ->method('applies') + ->will($this->returnValue(TRUE)); $builder2->expects($this->once()) ->method('build') ->will($this->returnValue($breadcrumb2)); @@ -117,11 +126,16 @@ public function testBuildWithMultipleApplyingBuilders() { public function testBuildWithOneNotApplyingBuilders() { $builder1 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $builder1->expects($this->once()) - ->method('build') - ->will($this->returnValue(NULL)); + ->method('applies') + ->will($this->returnValue(FALSE)); + $builder1->expects($this->never()) + ->method('build'); $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $breadcrumb2 = array('Test2'); + $builder2->expects($this->once()) + ->method('applies') + ->will($this->returnValue(TRUE)); $builder2->expects($this->once()) ->method('build') ->will($this->returnValue($breadcrumb2)); @@ -146,6 +160,9 @@ public function testBuildWithOneNotApplyingBuilders() { */ public function testBuildWithInvalidBreadcrumbResult() { $builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); + $builder->expects($this->once()) + ->method('applies') + ->will($this->returnValue(TRUE)); $builder->expects($this->once()) ->method('build') ->will($this->returnValue('invalid_result'));