Download the PHP package chamber-orchestra/menu-bundle without Composer
On this page you can find all versions of the php package chamber-orchestra/menu-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download chamber-orchestra/menu-bundle
More information about chamber-orchestra/menu-bundle
Files in chamber-orchestra/menu-bundle
Package menu-bundle
Short Description Symfony 8 navigation menu bundle with fluent tree builder, route-based active-item matching, role-based access control, runtime extensions for dynamic badges, PSR-6 tag-aware caching, and Twig rendering
License MIT
Homepage https://github.com/chamber-orchestra/menu-bundle
Informations about the package menu-bundle
ChamberOrchestra MenuBundle
A Symfony 8 bundle for building navigation menus, sidebars, and breadcrumbs — fluent tree builder, route-based active-item matching, role-based access control, runtime extensions for dynamic badges, PSR-6 tag-aware caching, and Twig rendering.
Features
- Fluent builder API —
add(),children(),end()for deeply-nested trees - Route-based matching —
RouteVotermarks the current item and its ancestors active; route values are treated as regex patterns - Custom voters — implement
VoterInterfaceto add custom matching logic alongside the built-inRouteVoter - Role-based access —
Accessorgates items by Symfony security roles; results are memoized per request - PSR-6 caching —
AbstractCachedNavigationcaches the item tree for 24 h with tag-based invalidation - Runtime extensions —
RuntimeExtensionInterfaceruns post-cache on every request for fresh dynamic data without rebuilding the tree - Badge support —
BadgeExtensionresolvesintand\Closurebadges at runtime; implementRuntimeExtensionInterfacefor service-injected dynamic badges - Counters —
CounterExtensionresolves multiple named counters (intor\Closure) at runtime - Icons —
IconExtensionmoves theiconoption intoextras['icon']at build time - Dividers —
DividerExtensionmarks items as dividers viaextras['divider']at build time - Visibility —
VisibilityExtensionresolvesvisible(bool or\Closure) at runtime intoextras['visible'] - Label translation —
TranslationExtensiontranslates item labels via Symfony'sTranslatorInterface(auto-disabled when no translator is available) - Breadcrumbs —
menu_breadcrumbs()Twig function returns the path from root to the current item - Raw tree access —
menu_get()Twig function returns the rootItemwithout rendering - Twig integration —
render_menu()function with fully customisable templates and optional default template - Bundle configuration — centralised config for default template, translation domain, and cache namespace
- Extension system — build-time
ExtensionInterfacefor cached option enrichment, runtimeRuntimeExtensionInterfacefor post-cache processing - DI autoconfiguration — implement an interface, done; no manual service tags required
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.5 |
| ext-ds | * |
| doctrine/collections | ^2.0 \|\| ^3.0 |
| symfony/* | ^8.0 |
| symfony/translation-contracts | ^3.4 |
| twig/twig | ^3.0 |
Installation
Register the bundle
Configuration
All values are optional with sensible defaults.
Quick Start
1. Create a navigation class
The class is auto-tagged as a navigation service — no YAML/XML service definition needed.
2. Create a Twig template
3. Render in Twig
Item Options
Options are passed as the second argument to MenuBuilder::add():
| Option | Type | Extension | Description |
|---|---|---|---|
label |
string |
LabelExtension |
Display text; falls back to item name if absent |
route |
string |
RoutingExtension |
Route name; generates uri and appends to routes |
route_params |
array |
RoutingExtension |
Route parameters passed to the URL generator |
route_type |
int |
RoutingExtension |
UrlGeneratorInterface::ABSOLUTE_PATH (default) or ABSOLUTE_URL |
routes |
array |
— | Additional routes that activate this item (supports regex) |
uri |
string |
— | Raw URI; set directly if not using route |
roles |
array |
— | Security roles all required to display the item (AND logic) |
icon |
string |
IconExtension |
Icon identifier; moved to extras['icon'] at build time |
divider |
bool |
DividerExtension |
When true, marks the item as a divider via extras['divider'] |
badge |
int\|\Closure |
BadgeExtension |
Badge count; resolved post-cache; stored in extras['badge'] |
counters |
array<string, int\|\Closure> |
CounterExtension |
Named counters; resolved post-cache; stored in extras['counters'] |
visible |
bool\|\Closure |
VisibilityExtension |
Visibility flag; resolved post-cache; stored in extras['visible'] |
translation_domain |
string |
TranslationExtension |
Per-item translation domain override |
attributes |
array |
CoreExtension |
HTML attributes merged onto the rendered element |
extras |
array |
CoreExtension |
Arbitrary extra data attached to the item |
Section items
Pass section: true to mark an item as a non-linkable section heading:
Caching
Navigation classes form a hierarchy — extend the one that fits your use case:
| Base class | TTL | Tags | Use case |
|---|---|---|---|
AbstractCachedNavigation |
24 h | chamber_orchestra_menu |
Menu structures (recommended) |
AbstractNavigation |
0 | none | Base class, no caching across requests |
ClosureNavigation |
0 (configurable) | none | Quick one-off menus; optionally cacheable |
All navigations are deduped within the same request via NavigationFactory. When a PSR-6 CacheInterface (tag-aware) is wired in, AbstractCachedNavigation stores the tree across requests. Without one, an in-memory ArrayAdapter is used automatically.
Dynamic data (badges, counters) does not require sacrificing the cache — use runtime extensions instead.
The default cache key is the fully-qualified class name; default TTL is 24 hours; default tag is chamber_orchestra_menu.
ClosureNavigation caching
ClosureNavigation is uncached by default (TTL 0), but you can opt in to caching by providing a unique cacheKey and a ttl:
Each cached ClosureNavigation must have a unique cacheKey — without one, all instances share the same key and overwrite each other.
The cache namespace prefix defaults to $NAVIGATION$ and can be changed via bundle configuration.
Route Matching
RouteVoter reads _route from the current request and compares it against each item's routes array. Route values are treated as regex patterns, so you can highlight an entire section:
Custom Voters
Implement VoterInterface to add custom matching logic. Custom voters are auto-tagged and used alongside RouteVoter:
Role-Based Access
The accessor variable is injected into every rendered template. Call hasAccess(item) to gate visibility:
hasAccess() returns true when:
- the item has no
rolesrestriction, or - the current user has all of the required roles (AND logic).
hasAccessToChildren(collection) returns true when any child in the collection is accessible.
Icons
The built-in IconExtension moves the icon option into extras['icon'] at build time, so the value is cached with the tree:
In Twig:
Dividers
The DividerExtension marks items as visual dividers at build time:
In Twig:
Visibility
The VisibilityExtension resolves the visible option at runtime. Pass a bool or a \Closure:
In Twig:
Badges
Via the badge option
The built-in BadgeExtension is a runtime extension that resolves the badge item option on every request. Pass an int or a \Closure:
Via a custom runtime extension
For service-injected dynamic data, implement RuntimeExtensionInterface. The tree stays cached; the extension runs post-cache on every request:
In Twig, read the badge via item.badge:
Counters
The CounterExtension resolves multiple named counters at runtime. Pass a array<string, int|\Closure>:
In Twig:
Label Translation
The TranslationExtension translates item labels using Symfony's TranslatorInterface. It runs at runtime (post-cache) so translated labels are always fresh.
- Default domain: configured via
chamber_orchestra_menu.translation.domain(defaults tomessages) - Per-item override: set the
translation_domainoption on an item - Empty labels are skipped
- Auto-disabled when no
TranslatorInterfaceservice is available in the container
Factory Extensions
Build-time extensions (cached)
Implement ExtensionInterface to enrich item options before the Item is created. Results are cached with the tree. Extensions are auto-tagged and sorted by priority (higher runs first; CoreExtension runs last at -10):
Built-in build-time extensions
| Extension | Option | Stored in | Description |
|---|---|---|---|
RoutingExtension |
route, route_params, route_type |
uri, routes |
Generates URI from route |
LabelExtension |
label |
label |
Falls back to item name |
IconExtension |
icon |
extras['icon'] |
Icon identifier |
DividerExtension |
divider |
extras['divider'] |
Divider flag |
CoreExtension |
attributes, extras |
— | Defaults (priority -10, runs last) |
Runtime extensions (post-cache)
Implement RuntimeExtensionInterface to apply fresh data after every cache fetch. processItem() is called on every Item in the tree:
Built-in runtime extensions
| Extension | Option | Stored in | Description |
|---|---|---|---|
BadgeExtension |
badge |
extras['badge'] |
Single badge count (int\|\Closure) |
CounterExtension |
counters |
extras['counters'] |
Named counters map |
VisibilityExtension |
visible |
extras['visible'] |
Visibility flag (bool\|\Closure) |
TranslationExtension |
translation_domain |
label (via setLabel()) |
Translates labels |
DI Autoconfiguration
Implement an interface and you're done — no manual service tags required:
| Interface | Auto-tag |
|---|---|
NavigationInterface |
chamber_orchestra_menu.navigation |
ExtensionInterface |
chamber_orchestra_menu.factory.extension |
RuntimeExtensionInterface |
chamber_orchestra_menu.factory.runtime_extension |
VoterInterface |
chamber_orchestra_menu.matcher.voter |
Breadcrumbs
The menu_breadcrumbs() Twig function returns the path from root to the current item (root excluded):
Returns an empty array when no item is currently active.
Twig Reference
Template variables (available inside render_menu templates):
| Variable | Type | Description |
|---|---|---|
root |
Item |
Root item — iterate to get top-level items |
matcher |
Matcher |
Call isCurrent(item) / isAncestor(item) |
accessor |
Accessor |
Call hasAccess(item) / hasAccessToChildren(collection) |
Testing
License
MIT. See LICENSE.
All versions of menu-bundle with dependencies
ext-ds Version *
doctrine/collections Version ^2.6 || ^3.1
symfony/cache-contracts Version ^3.7
symfony/config Version 8.1.*
symfony/dependency-injection Version 8.1.*
symfony/http-foundation Version 8.1.*
symfony/http-kernel Version 8.1.*
symfony/routing Version 8.1.*
symfony/security-core Version 8.1.*
symfony/translation-contracts Version ^3.7
twig/twig Version ^3.29