Skip to content
Snippets Groups Projects
Verified Commit 78bbe4db authored by Lee Rowlands's avatar Lee Rowlands
Browse files

Issue #3482691 by james.williams, arunkumark, kristiaanvandeneynde,...

Issue #3482691 by james.williams, arunkumark, kristiaanvandeneynde, smustgrave: BreadcrumbManager ignores cacheability when no builders apply
parent e6b0b85e
No related branches found
No related tags found
No related merge requests found
...@@ -83,16 +83,18 @@ public function build(RouteMatchInterface $route_match) { ...@@ -83,16 +83,18 @@ public function build(RouteMatchInterface $route_match) {
} }
$breadcrumb = $builder->build($route_match); $breadcrumb = $builder->build($route_match);
if ($breadcrumb instanceof Breadcrumb) { if ($breadcrumb instanceof Breadcrumb) {
$context['builder'] = $builder; $context['builder'] = $builder;
$breadcrumb->addCacheableDependency($cacheable_metadata);
break; break;
} }
else { else {
throw new \UnexpectedValueException('Invalid breadcrumb returned by ' . get_class($builder) . '::build().'); throw new \UnexpectedValueException('Invalid breadcrumb returned by ' . get_class($builder) . '::build().');
} }
} }
// Ensure all collected cacheability is applied.
$breadcrumb->addCacheableDependency($cacheable_metadata);
// Allow modules to alter the breadcrumb. // Allow modules to alter the breadcrumb.
$this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context); $this->moduleHandler->alter('system_breadcrumb', $breadcrumb, $route_match, $context);
......
...@@ -577,3 +577,11 @@ menu_test.breadcrumb3: ...@@ -577,3 +577,11 @@ menu_test.breadcrumb3:
_title: 'Normal title' _title: 'Normal title'
requirements: requirements:
_access: 'TRUE' _access: 'TRUE'
menu_test.skippable-breadcrumb:
path: '/menu-test/skippable-breadcrumb'
defaults:
_controller: '\Drupal\menu_test\Controller\MenuTestController::menuTestCallback'
_title: 'Normal title'
requirements:
_access: 'TRUE'
<?php
declare(strict_types=1);
namespace Drupal\menu_test;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Symfony\Component\DependencyInjection\Reference;
/**
* Decorate core's default path-based breadcrumb builder when it is available.
*/
class MenuTestServiceProvider implements ServiceModifierInterface {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container): void {
if ($container->has('system.breadcrumb.default')) {
$container->register('menu_test.breadcrumb.default', SkippablePathBasedBreadcrumbBuilder::class)
->setDecoratedService('system.breadcrumb.default')
->addArgument(new Reference('menu_test.breadcrumb.default.inner'))
->addArgument(new Reference('request_stack'));
}
}
}
<?php
declare(strict_types=1);
namespace Drupal\menu_test;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* A path-based breadcrumb builder can be skipped from applying.
*/
class SkippablePathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
public function __construct(
protected BreadcrumbBuilderInterface $pathBasedBreadcrumbBuilder,
protected RequestStack $requestStack,
) {}
/**
* {@inheritdoc}
*/
public function applies(RouteMatchInterface $route_match, ?CacheableMetadata $cacheable_metadata = NULL): bool {
$query_arg = 'menu_test_skip_breadcrumbs';
$cacheable_metadata?->addCacheContexts(['url.query_args:' . $query_arg]);
// Apply unless the query argument is present.
return !$this->requestStack->getCurrentRequest()->query->has($query_arg);
}
/**
* {@inheritdoc}
*/
public function build(RouteMatchInterface $route_match): Breadcrumb {
return $this->pathBasedBreadcrumbBuilder->build($route_match);
}
}
...@@ -388,6 +388,15 @@ public function testBreadCrumbs(): void { ...@@ -388,6 +388,15 @@ public function testBreadCrumbs(): void {
$this->drupalGet('menu-test/breadcrumb1/breadcrumb2/breadcrumb3'); $this->drupalGet('menu-test/breadcrumb1/breadcrumb2/breadcrumb3');
$this->assertSession()->responseContains('<script>alert(12);</script>'); $this->assertSession()->responseContains('<script>alert(12);</script>');
$this->assertSession()->assertEscaped('<script>alert(123);</script>'); $this->assertSession()->assertEscaped('<script>alert(123);</script>');
// Assert that the breadcrumb cacheability is respected after not applying.
$this->assertBreadcrumb(Url::fromRoute('menu_test.skippable-breadcrumb', [], [
'query' => [
'menu_test_skip_breadcrumbs' => 'yes',
],
]), []);
$trail = $home + ['menu-test' => 'Menu test root'];
$this->assertBreadcrumb(Url::fromRoute('menu_test.skippable-breadcrumb'), $trail);
} }
/** /**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment