airria/breadcrumbtrail-bundle
Installation
composer require airria/breadcrumbtrail-bundle
Add to config/bundles.php:
Airria\APYBreadcrumbTrailBundle\APYBreadcrumbTrailBundle::class => ['all' => true],
Enable in config/packages/apy_breadcrumb_trail.yaml
apy_breadcrumb_trail:
enabled: true
# Optional: Default options
default_options:
separator: '›'
first_item: true
First Use Case: Annotated Controller
use Airria\APYBreadcrumbTrailBundle\Annotation\Breadcrumb;
class ProductController extends AbstractController
{
#[Breadcrumb('Home', route: 'homepage')]
#[Breadcrumb('Products', route: 'product_index')]
public function show(Product $product): Response
{
return $this->render('product/show.html.twig', ['product' => $product]);
}
}
Render in Twig
{{ render(apy_breadcrumb_trail()) }}
use Airria\APYBreadcrumbTrailBundle\Attribute\Breadcrumb;
#[Breadcrumb('Dashboard', route: 'dashboard')]
#[Breadcrumb('Projects', route: 'project_index')]
public function index(): Response
{
return $this->render('project/index.html.twig');
}
public function show(Product $product): Response
{
$this->breadcrumbTrail()
->add('Home', 'homepage')
->add('Products', 'product_index')
->add($product->name, 'product_show', ['id' => $product->id]);
return $this->render('product/show.html.twig');
}
{{ render(apy_breadcrumb_trail({
'separator': ' » ',
'first_item': false,
'exclude_current': true
})) }}
// src/EventListener/BreadcrumbListener.php
public function onKernelRequest(RequestEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$trail = $event->getRequest()->attributes->get('breadcrumb_trail');
if ($trail) {
$this->breadcrumbTrail()->merge($trail);
}
}
Extend the default Twig extension:
// src/Twig/BreadcrumbExtension.php
class CustomBreadcrumbExtension extends \Airria\APYBreadcrumbTrailBundle\Twig\BreadcrumbExtension
{
public function getBreadcrumbTrailHtml(array $options = []): string
{
// Custom logic (e.g., add icons, modify classes)
return parent::getBreadcrumbTrailHtml($options);
}
}
Register as a service and tag it to replace the default.
Annotation vs. Attribute Conflicts
@Breadcrumb) and attributes (#[Breadcrumb]), the last defined takes precedence.Route Generation Failures
routeParameters in the attribute:
#[Breadcrumb('Edit', route: 'product_edit', routeParameters: ['id' => $product->id])]
Caching Issues
Twig Auto-escaping
|raw:
{{ render(apy_breadcrumb_trail())|raw }}
{{ dump(apy_breadcrumb_trail().getItems()) }}
router service to verify routes:
$this->container->get('router')->generate('product_index');
APY_BREADCRUMB_TRAIL_DEBUG=true in .env to log unresolved routes.Custom Trail Providers
Implement BreadcrumbTrailProviderInterface to fetch breadcrumbs from a database or API.
Modify Trail Items
Use the BreadcrumbTrailEvent (dispatches after generation):
$eventDispatcher->addListener(BreadcrumbTrailEvents::POST_BUILD, function (BreadcrumbTrailEvent $event) {
$event->getTrail()->add('Custom Item', '#');
});
Override Twig Rendering
Replace the default Twig extension by binding your own service with the apy_breadcrumb_trail.twig.extension tag.
Localization Support
Use Symfony’s translation system with the translation_domain option:
#[Breadcrumb('Products', route: 'product_index', translationDomain: 'messages')]
How can I help you explore Laravel packages today?