Installation:
composer require baconmanager/menu-bundle
Register bundles in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony <4):
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
Bacon\Bundle\MenuBundle\BaconMenuBundle::class => ['all' => true],
Configure config/packages/knp_menu.yaml:
knp_menu:
twig:
template: BaconCoreBundle:partial:menu.html.twig
templating: false
default_renderer: twig
First Use Case:
Create a menu builder class (e.g., src/Menu/Builder.php):
namespace App\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function addMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('Home', ['route' => 'home']);
return $menu;
}
}
Render the menu in Twig:
{{ bacon_menu_full_render() }}
Organize Builders:
Group builders by feature (e.g., AdminBuilder, FrontendBuilder) in src/Menu/ with clear naming conventions (e.g., AdminMenuBuilder).
Dependency Injection:
Use ContainerAwareTrait (Symfony ≥2.8) or ContainerAware (Symfony ≤2.7) to access services like translator, security, or router:
$translator = $this->container->get('translator');
$routeGenerator = $this->container->get('router')->getContext()->getParameter('router.request_context');
Dynamic Menus: Fetch menu items from the database or API:
$items = $this->container->get('doctrine')->getRepository(Item::class)->findAll();
foreach ($items as $item) {
$menu->addChild($item->getName(), ['route' => 'item_show', 'id' => $item->getId()]);
}
Conditional Rendering:
Use Symfony’s security component to show/hide items based on roles:
if ($this->container->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
$menu->addChild('Admin', ['route' => 'admin_dashboard']);
}
Reusable Components: Extract common menu logic into base classes or traits:
trait MenuBuilderTrait {
protected function addRouteItem(MenuItemInterface $menu, string $label, string $route, array $options = []): MenuItemInterface {
return $menu->addChild($label, ['route' => $route] + $options);
}
}
Menu Registration:
Register builders in config/services.yaml (Symfony 4+) or services.yml:
services:
App\Menu\AdminMenuBuilder:
tags: ['knp_menu.menu_builder', { alias: 'admin' }]
bacon_menu_full_render() for full menus or bacon_menu_render('menu_name') for specific menus.BaconCoreBundle:partial:menu.html.twig) by extending it in your theme:
{% extends 'BaconCoreBundle:partial:menu.html.twig' %}
{% block menu_item %}{{ item.label }} <span class="badge">{{ item.attributes.badge }}</span>{% endblock %}
Bundle Order:
Ensure KnpMenuBundle is registered before BaconMenuBundle in bundles.php/AppKernel.php. Otherwise, the bundle may fail to override templates.
Template Overrides:
If bacon_menu_full_render() doesn’t work, verify:
BaconCoreBundle:partial:menu.html.twig) exists in the bundle’s Resources/views/partial/menu.html.twig.twig.paths in config/packages/twig.yaml).Symfony Version Mismatch:
ContainerAwareTrait and ContainerAwareInterface.ContainerAware (deprecated in newer Symfony versions).Caching Issues: Clear the cache after adding new builders or templates:
php bin/console cache:clear
Menu Builder Aliases:
If using knp_menu.menu_builder tags, ensure the alias matches the menu name used in Twig (e.g., {{ bacon_menu_render('admin') }} requires alias: 'admin' in the service tag).
Dump Menu Structure: Add this to your builder to debug:
$menu->setChildrenAttribute('data-debug', true);
Then inspect the rendered HTML for a data-debug attribute.
Check Registered Builders: Run:
php bin/console debug:container | grep menu_builder
To verify builders are correctly registered.
Icons and Attributes:
Use setAttribute() for custom data (e.g., icons, badges):
$menu->addChild('Items', ['route' => 'items'])
->setAttribute('icon', '<i class="fas fa-list"></i>')
->setAttribute('badge', $this->container->get('item.repository')->count());
Localization: Always use the translator for labels:
$menu->addChild($this->container->get('translator')->trans('menu.home'));
Performance:
For large menus, lazy-load items or use setChildrenAttribute('cache', true) to cache submenus.
Extending the Bundle:
Override the default template by copying BaconCoreBundle:partial:menu.html.twig to your theme’s templates/partials/ and extending it.
Symfony 5+:
If using Symfony Flex, ensure knp-menu-bundle and baconmenu-bundle are auto-loaded. Run:
composer require knplabs/knp-menu-bundle
composer require baconmanager/menu-bundle
Menu Events:
Listen to knp_menu.menu_event to dynamically modify menus:
// config/services.yaml
App\EventListener\MenuListener:
tags:
- { name: 'kernel.event_listener', event: 'knp_menu.menu_event', method: 'onMenuEvent' }
How can I help you explore Laravel packages today?