Installation:
composer require byte-artist/menu-bundle
Enable the bundle in config/bundles.php:
ByteArtist\MenuBundle\MenuBundle::class => ['all' => true],
Basic Configuration:
Create config/packages/byte_artist_menu.yaml (or merge into config/packages/framework.yaml):
menu:
type: default
brand_name: "MyApp"
pages:
home:
path: home
label: "Home"
First Use Case: Render the menu in a Twig template:
{{ render(controller('ByteArtistMenuBundle:Menu:render')) }}
Or use the Twig extension directly:
{{ menu('default') }}
Centralized Menu Definition:
Define menus in menu.yaml under config/packages/byte_artist_menu.yaml (or a custom path via config).
Example:
menu:
main:
type: horizontal
pages:
dashboard:
path: dashboard
label: "Dashboard"
icon: "fas fa-tachometer-alt"
products:
path: product_index
label: "Products"
pages: # Nested submenu
list:
path: product_list
label: "List"
Dynamic Menu Rendering: Use Twig extensions to render menus dynamically:
{% for menu in menu('main') %}
{{ menu.render() }}
{% endfor %}
Route-Based Active State:
The bundle auto-detects active routes via Symfony’s router. No manual is_active flags needed.
Dependency Injection: Access the menu service in controllers:
public function __construct(private MenuManager $menuManager) {}
public function showMenu()
{
$menu = $this->menuManager->getMenu('main');
return $this->render('menu.html.twig', ['menu' => $menu]);
}
Event-Driven Extensions:
Extend menu behavior via events (e.g., MenuBuilderEvent):
// src/EventListener/CustomMenuListener.php
public function onMenuBuild(MenuBuildEvent $event) {
$event->getMenu()->addItem('custom_item', ['path' => 'custom_route']);
}
Register in services.yaml:
services:
App\EventListener\CustomMenuListener:
tags:
- { name: kernel.event_listener, event: menu.build, method: onMenuBuild }
templates/ByteArtistMenuBundle/Menu/ (e.g., default.html.twig).
Example override for horizontal.html.twig:
<nav class="custom-nav">
<ul>
{% for item in menu %}
<li class="{{ item.isActive ? 'active' : '' }}">
<a href="{{ path(item.path) }}">{{ item.label }}</a>
</li>
{% endfor %}
</ul>
</nav>
Route Resolution Issues:
debug:router to verify:
php bin/console debug:router
{id}), use exact route names or handle in a custom MenuBuilder.Translation Quirks:
label_home). Use trans() in Twig if needed:
{{ trans(menu.item.label) }}
Caching: Menus are cached by default. Clear cache after config changes:
php bin/console cache:clear
Dump Menu Structure:
Use Twig’s dump() to inspect the menu object:
{{ dump(menu('main')) }}
Or in PHP:
var_dump($this->menuManager->getMenu('main')->toArray());
Active State Debugging:
Check if isActive logic works as expected. Override isActive() in a custom MenuItem class if needed.
Custom Menu Types:
Create a new menu type by implementing MenuBuilderInterface:
class CustomMenuBuilder implements MenuBuilderInterface {
public function build(Menu $menu, array $config) {
// Custom logic
}
}
Register in services.yaml:
services:
App\Menu\CustomMenuBuilder:
tags:
- { name: byte_artist_menu.builder, type: "custom" }
Dynamic Menu Items:
Use the menu.build event to add items programmatically (e.g., based on user roles):
public function onMenuBuild(MenuBuildEvent $event) {
if ($this->security->isGranted('ROLE_ADMIN')) {
$event->getMenu()->addItem('admin', ['path' => 'admin_dashboard']);
}
}
Disable Caching:
Set cache: false in menu.yaml for development:
menu:
cache: false
Asset Management:
Override CSS/JS by setting use_orig_css: false and providing custom paths:
menu:
css_path: "/custom/css/menu.css"
js_path: "/custom/js/menu.js"
How can I help you explore Laravel packages today?