Installation
composer require becklyn/menu
Add the bundle to config/bundles.php (Symfony 4.4+):
Becklyn\MenuBundle\BecklynMenuBundle::class => ['all' => true],
First Menu Definition Define a menu in a service or controller:
use Becklyn\MenuBundle\Menu\Menu;
use Becklyn\MenuBundle\Menu\MenuItem;
$menu = new Menu();
$menu->addItem(new MenuItem('Home', 'home'));
$menu->addItem(new MenuItem('About', 'about'));
Rendering Use Twig to render the menu:
{{ render(menu) }}
Or pass it directly to a template:
return $this->render('template.html.twig', ['menu' => $menu]);
// src/Controller/MenuController.php
public function index(MenuBuilder $menuBuilder)
{
$menu = $menuBuilder->create()
->add('Home', 'home')
->add('Products', 'products', ['children' => [
'Product 1', 'Product 2'
]])
->add('Contact', 'contact');
return $this->render('index.html.twig', ['menu' => $menu]);
}
Use the MenuBuilder service for fluent menu creation:
$menu = $menuBuilder->create()
->add('Dashboard', 'dashboard', [
'icon' => 'fas fa-tachometer-alt',
'active' => $this->isCurrentRoute('dashboard')
])
->add('Settings', 'settings', [
'children' => $this->buildSettingsSubmenu()
]);
Leverage Symfony’s dependency injection to fetch menus dynamically:
// src/Service/MenuFactory.php
public function createMainMenu(EntityManagerInterface $em)
{
$menu = $menuBuilder->create();
$categories = $em->getRepository(Category::class)->findAll();
foreach ($categories as $category) {
$menu->add($category->getName(), 'category_' . $category->getId());
}
return $menu;
}
Extend Twig with custom menu rendering:
{# templates/partials/navbar.html.twig #}
<nav>
<ul class="nav">
{% for item in menu.items %}
<li class="nav-item {% if item.active %}active{% endif %}">
<a href="{{ path(item.route) }}" class="nav-link">
{{ item.label }}
</a>
{% if item.children|length > 0 %}
<ul class="dropdown-menu">
{% include 'partials/_menu_items.html.twig' with {'items': item.children} %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
Use the MenuItem helper to auto-activate based on current route:
$menu->addItem(
new MenuItem('Profile', 'profile', [
'active' => $this->get('router')->getContext()->getRequest()->attributes->get('_route') === 'profile_show'
])
);
Cache menus for performance:
$menu = $menuBuilder->create();
$menuCache = $this->get('cache')->get('main_menu');
if (!$menuCache) {
$menuCache = $menu;
$this->get('cache')->set('main_menu', $menu, 3600); // Cache for 1 hour
}
Route Resolution
routes.yaml or routing.yml before using them in menus.{{ dump(menu.items[0].route) }} in Twig to verify route names.Circular References
Twig Rendering Quirks
{{ render(menu) }} fails, ensure the BecklynMenuBundle is properly registered in bundles.php and the Twig environment is configured.Active State Logic
active state is static by default. For dynamic activation (e.g., based on user roles), override the isActive() method in a custom MenuItem class.Dump Menu Structure
{{ dump(menu) }}
or in PHP:
var_dump($menu->toArray());
Check Route Names Use Symfony’s route debugger or:
php bin/console debug:router
Custom Menu Item Classes
Extend MenuItem to add custom logic:
class CustomMenuItem extends MenuItem
{
public function isActive(): bool
{
// Custom logic here
return parent::isActive() || $this->hasSpecialCondition();
}
}
Event Listeners Use Symfony events to modify menus globally:
// src/EventListener/MenuListener.php
public function onMenuBuild(MenuBuildEvent $event)
{
$menu = $event->getMenu();
$menu->addItem(new MenuItem('Admin', 'admin', ['role' => 'ROLE_ADMIN']));
}
Register the listener in services.yaml:
services:
App\EventListener\MenuListener:
tags:
- { name: kernel.event_listener, event: becklyn.menu.build, method: onMenuBuild }
Twig Extensions Create a custom Twig extension for advanced rendering:
// src/Twig/MenuExtension.php
class MenuExtension extends \Twig\Extension\AbstractExtension
{
public function getFunctions()
{
return [
new \Twig\TwigFunction('render_menu', [$this, 'renderMenu']),
];
}
public function renderMenu(Menu $menu, string $template)
{
return $this->env->render('@BecklynMenu/' . $template, ['menu' => $menu]);
}
}
Default Twig Path
The bundle looks for Twig templates in @BecklynMenu/. Override this in config/packages/becklyn_menu.yaml:
becklyn_menu:
twig:
template_path: 'templates/partials/menus'
Menu Item Options
Use data-* attributes for custom options:
$menu->addItem(new MenuItem('Custom', 'custom', [
'data-custom' => 'value',
'class' => 'custom-class'
]));
Access in Twig:
<a href="{{ path(item.route) }}" class="{{ item.class }}">...</a>
How can I help you explore Laravel packages today?