Commit c478bf40 authored by Dries's avatar Dries

Issue #2150621 by damiankloip: Separate applies and build logic for breadcrumb builders.

parent 17cc6dab
...@@ -12,15 +12,27 @@ ...@@ -12,15 +12,27 @@
*/ */
interface BreadcrumbBuilderInterface { 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. * Builds the breadcrumb.
* *
* @param array $attributes * @param array $attributes
* Attributes representing the current page. * Attributes representing the current page.
* *
* @return array|null * @return array
* A render array for the breadcrumbs or NULL to let other builders decide. * A render array for the breadcrumbs. Returning an empty array will
* Returning empty array will suppress all breadcrumbs. * suppress all breadcrumbs.
*/ */
public function build(array $attributes); public function build(array $attributes);
......
...@@ -65,6 +65,13 @@ public function addBuilder(BreadcrumbBuilderInterface $builder, $priority) { ...@@ -65,6 +65,13 @@ public function addBuilder(BreadcrumbBuilderInterface $builder, $priority) {
$this->sortedBuilders = NULL; $this->sortedBuilders = NULL;
} }
/**
* {@inheritdoc}
*/
public function applies(array $attributes) {
return TRUE;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -74,12 +81,14 @@ public function build(array $attributes) { ...@@ -74,12 +81,14 @@ public function build(array $attributes) {
// Call the build method of registered breadcrumb builders, // Call the build method of registered breadcrumb builders,
// until one of them returns an array. // until one of them returns an array.
foreach ($this->getSortedBuilders() as $builder) { foreach ($this->getSortedBuilders() as $builder) {
$build = $builder->build($attributes); if (!$builder->applies($attributes)) {
if (!isset($build)) { // The builder does not apply, so we continue with the other builders.
// The builder returned NULL, so we continue with the other builders.
continue; continue;
} }
elseif (is_array($build)) {
$build = $builder->build($attributes);
if (is_array($build)) {
// The builder returned an array of breadcrumb links. // The builder returned an array of breadcrumb links.
$breadcrumb = $build; $breadcrumb = $build;
$context['builder'] = $builder; $context['builder'] = $builder;
......
...@@ -55,34 +55,41 @@ public function __construct(EntityManagerInterface $entity_manager, AccessManage ...@@ -55,34 +55,41 @@ public function __construct(EntityManagerInterface $entity_manager, AccessManage
$this->account = $account; $this->account = $account;
} }
/**
* {@inheritdoc}
*/
public function applies(array $attributes) {
return !empty($attributes['node'])
&& ($attributes['node'] instanceof NodeInterface)
&& !empty($attributes['node']->book);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function build(array $attributes) { public function build(array $attributes) {
if (!empty($attributes['node']) && $attributes['node'] instanceof NodeInterface && !empty($attributes['node']->book)) { $mlids = array();
$mlids = array(); $links = array($this->l($this->t('Home'), '<front>'));
$links = array($this->l($this->t('Home'), '<front>')); $book = $attributes['node']->book;
$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; $depth = 1;
// We skip the current node.
while (!empty($book['p' . ($depth + 1)])) { while (!empty($book['p' . ($depth + 1)])) {
$mlids[] = $book['p' . $depth]; if (!empty($menu_links[$book['p' . $depth]]) && ($menu_link = $menu_links[$book['p' . $depth]])) {
$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);
$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);
}
} }
$depth++;
} }
$depth++;
} }
return $links;
} }
return $links;
} }
} }
...@@ -33,23 +33,29 @@ public function __construct(EntityManagerInterface $entity_manager) { ...@@ -33,23 +33,29 @@ public function __construct(EntityManagerInterface $entity_manager) {
$this->entityManager = $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} * {@inheritdoc}
*/ */
public function build(array $attributes) { public function build(array $attributes) {
if (isset($attributes[RouteObjectInterface::ROUTE_NAME]) && $attributes[RouteObjectInterface::ROUTE_NAME] == 'comment.reply' $breadcrumb = array();
&& isset($attributes['entity_type'])
&& isset($attributes['entity_id']) $breadcrumb[] = $this->l($this->t('Home'), '<front>');
&& isset($attributes['field_name']) $entity = $this->entityManager
) { ->getStorageController($attributes['entity_type'])
$breadcrumb[] = $this->l($this->t('Home'), '<front>'); ->load($attributes['entity_id']);
$entity = $this->entityManager $uri = $entity->uri();
->getStorageController($attributes['entity_type']) $breadcrumb[] = l($entity->label(), $uri['path'], $uri['options']);
->load($attributes['entity_id']); return $breadcrumb;
$uri = $entity->uri();
$breadcrumb[] = l($entity->label(), $uri['path'], $uri['options']);
return $breadcrumb;
}
} }
} }
...@@ -55,20 +55,25 @@ public function __construct(EntityManagerInterface $entity_manager, ConfigFactor ...@@ -55,20 +55,25 @@ public function __construct(EntityManagerInterface $entity_manager, ConfigFactor
$this->forumManager = $forum_manager; $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} * {@inheritdoc}
*/ */
public function build(array $attributes) { public function build(array $attributes) {
if (!empty($attributes[RouteObjectInterface::ROUTE_NAME])) { if ($attributes[RouteObjectInterface::ROUTE_NAME] == 'node.view') {
$route_name = $attributes[RouteObjectInterface::ROUTE_NAME]; return $this->forumPostBreadcrumb($attributes['node']);
if ($route_name == 'node.view' && isset($attributes['node'])) { }
if ($this->forumManager->checkNodeType($attributes['node'])) { elseif ($attributes[RouteObjectInterface::ROUTE_NAME] == 'forum.page') {
return $this->forumPostBreadcrumb($attributes['node']); return $this->forumTermBreadcrumb($attributes['taxonomy_term']);
}
}
if ($route_name == 'forum.page' && isset($attributes['taxonomy_term'])) {
return $this->forumTermBreadcrumb($attributes['taxonomy_term']);
}
} }
} }
......
...@@ -102,6 +102,13 @@ public function __construct(Request $request, EntityManagerInterface $entity_man ...@@ -102,6 +102,13 @@ public function __construct(Request $request, EntityManagerInterface $entity_man
$this->titleResolver = $title_resolver; $this->titleResolver = $title_resolver;
} }
/**
* {@inheritdoc}
*/
public function applies(array $attributes) {
return TRUE;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
......
...@@ -15,24 +15,32 @@ ...@@ -15,24 +15,32 @@
*/ */
class TermBreadcrumbBuilder extends BreadcrumbBuilderBase { 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} * {@inheritdoc}
*/ */
public function build(array $attributes) { 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) { $term = $attributes['taxonomy_term'];
// @todo This overrides any other possible breadcrumb and is a pure // @todo This overrides any other possible breadcrumb and is a pure
// hard-coded presumption. Make this behavior configurable per // hard-coded presumption. Make this behavior configurable per
// vocabulary or term. // vocabulary or term.
$breadcrumb = array(); $breadcrumb = array();
while ($parents = taxonomy_term_load_parents($term->id())) { while ($parents = taxonomy_term_load_parents($term->id())) {
$term = array_shift($parents); $term = array_shift($parents);
$breadcrumb[] = $this->l($term->label(), 'taxonomy.term_page', array('taxonomy_term' => $term->id())); $breadcrumb[] = $this->l($term->label(), 'taxonomy.term_page', array('taxonomy_term' => $term->id()));
}
$breadcrumb[] = $this->l($this->t('Home'), '<front>');
$breadcrumb = array_reverse($breadcrumb);
return $breadcrumb;
} }
$breadcrumb[] = $this->l($this->t('Home'), '<front>');
$breadcrumb = array_reverse($breadcrumb);
return $breadcrumb;
} }
} }
...@@ -70,6 +70,10 @@ public function testBuildWithSingleBuilder() { ...@@ -70,6 +70,10 @@ public function testBuildWithSingleBuilder() {
$attributes = array('key' => 'value'); $attributes = array('key' => 'value');
$builder->expects($this->once())
->method('applies')
->will($this->returnValue(TRUE));
$builder->expects($this->once()) $builder->expects($this->once())
->method('build') ->method('build')
->will($this->returnValue($breadcrumb)); ->will($this->returnValue($breadcrumb));
...@@ -89,11 +93,16 @@ public function testBuildWithSingleBuilder() { ...@@ -89,11 +93,16 @@ public function testBuildWithSingleBuilder() {
*/ */
public function testBuildWithMultipleApplyingBuilders() { public function testBuildWithMultipleApplyingBuilders() {
$builder1 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $builder1 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$builder1->expects($this->never())
->method('applies');
$builder1->expects($this->never()) $builder1->expects($this->never())
->method('build'); ->method('build');
$builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$breadcrumb2 = array('<a href="/example2">Test2</a>'); $breadcrumb2 = array('<a href="/example2">Test2</a>');
$builder2->expects($this->once())
->method('applies')
->will($this->returnValue(TRUE));
$builder2->expects($this->once()) $builder2->expects($this->once())
->method('build') ->method('build')
->will($this->returnValue($breadcrumb2)); ->will($this->returnValue($breadcrumb2));
...@@ -117,11 +126,16 @@ public function testBuildWithMultipleApplyingBuilders() { ...@@ -117,11 +126,16 @@ public function testBuildWithMultipleApplyingBuilders() {
public function testBuildWithOneNotApplyingBuilders() { public function testBuildWithOneNotApplyingBuilders() {
$builder1 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $builder1 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$builder1->expects($this->once()) $builder1->expects($this->once())
->method('build') ->method('applies')
->will($this->returnValue(NULL)); ->will($this->returnValue(FALSE));
$builder1->expects($this->never())
->method('build');
$builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$breadcrumb2 = array('<a href="/example2">Test2</a>'); $breadcrumb2 = array('<a href="/example2">Test2</a>');
$builder2->expects($this->once())
->method('applies')
->will($this->returnValue(TRUE));
$builder2->expects($this->once()) $builder2->expects($this->once())
->method('build') ->method('build')
->will($this->returnValue($breadcrumb2)); ->will($this->returnValue($breadcrumb2));
...@@ -146,6 +160,9 @@ public function testBuildWithOneNotApplyingBuilders() { ...@@ -146,6 +160,9 @@ public function testBuildWithOneNotApplyingBuilders() {
*/ */
public function testBuildWithInvalidBreadcrumbResult() { public function testBuildWithInvalidBreadcrumbResult() {
$builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface'); $builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
$builder->expects($this->once())
->method('applies')
->will($this->returnValue(TRUE));
$builder->expects($this->once()) $builder->expects($this->once())
->method('build') ->method('build')
->will($this->returnValue('invalid_result')); ->will($this->returnValue('invalid_result'));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment