Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Menu Bundle Laravel Package

chamber-orchestra/menu-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the Bundle**
   Add to your `composer.json`:
   ```bash
   composer require chamber-orchestra/menu-bundle

Enable in config/bundles.php:

ChamberOrchestra\MenuBundle\ChamberOrchestraMenuBundle::class => ['all' => true],
  1. Configure the Bundle Publish the default config:

    php bin/console chamber-orchestra:menu:config
    

    Edit config/packages/chamber_orchestra_menu.yaml to define your menu structure (e.g., main_menu, footer_menu).

  2. First Use Case: Render a Menu in Twig Inject the MenuBuilder service and render in a Twig template:

    {{ render_menu('main_menu') }}
    

    Or directly in PHP:

    $menu = $menuBuilder->build('main_menu');
    $menuRenderer->render($menu);
    
  3. Define a Menu Create a YAML config (e.g., config/menus/main_menu.yaml):

    main_menu:
      items:
        - label: 'Home'
          route: 'homepage'
          active: true
        - label: 'Products'
          route: 'products.index'
          children:
            - label: 'Laptops'
              route: 'products.laptops'
    

Implementation Patterns

1. Fluent Tree Builder API

Dynamically build menus in code (e.g., for dynamic content):

$menu = $menuBuilder->create('dynamic_menu')
    ->addItem('Dashboard', 'dashboard')
    ->addItem('Settings')
        ->addChild('Profile', 'profile.edit')
        ->addChild('Billing', 'billing.index')
    ->end()
    ->get();

2. Route-Based Active Item Matching

Automatically highlight the current route:

items:
  - label: 'Blog'
    route: 'blog.index'
    active: true  # Optional; auto-detected if `active` is omitted

Override logic via active_matcher in config:

chamber_orchestra_menu:
    matchers:
        active:
            class: App\Matcher\CustomActiveMatcher

3. Role-Based Access Control (RBAC)

Restrict menu items by user roles:

items:
  - label: 'Admin'
    route: 'admin.dashboard'
    roles: ['ROLE_ADMIN']

Or dynamically in code:

$menu->addItem('Admin', 'admin.dashboard')
    ->setRoles(['ROLE_ADMIN']);

4. Dynamic Badges

Add badges (e.g., notifications) to menu items:

items:
  - label: 'Messages'
    route: 'messages.index'
    badge: { text: '3', type: 'danger' }

Or programmatically:

$menu->addItem('Messages', 'messages.index')
    ->setBadge('3', 'danger');

5. PSR-6 Caching

Cache menus for performance:

chamber_orchestra_menu:
    cache:
        enabled: true
        pool: 'app.cache.menu'

Clear cache via:

php bin/console cache:clear chamber_orchestra_menu

6. Twig Integration

Use Twig helpers for rendering:

{% render_menu 'main_menu', {
    'active_class': 'active',
    'badge_class': 'badge',
    'depth_limit': 2
} %}

Customize templates by overriding: templates/chamber_orchestra_menu/menu.html.twig.

7. Event-Driven Extensions

Listen to menu-building events (e.g., MenuBuildEvent):

// src/EventListener/AddDynamicItemsListener.php
public function onMenuBuild(MenuBuildEvent $event) {
    $event->getMenu()->addItem('Dynamic Item', '#');
}

Register in services.yaml:

services:
    App\EventListener\AddDynamicItemsListener:
        tags:
            - { name: 'kernel.event_listener', event: 'menu.build', method: 'onMenuBuild' }

Gotchas and Tips

Pitfalls

  1. Circular References in Menus Avoid recursive menu structures (e.g., a child pointing to its parent). The bundle throws a CircularReferenceException if detected.

  2. Route Matching Edge Cases

    • Dynamic Routes: Use route_parameters to match dynamic segments:
      route: 'product.show'
      route_parameters: { slug: 'laptop' }
      
    • External URLs: Prefix with http:// or https:// to bypass route matching:
      route: 'https://example.com'
      
  3. Cache Invalidation Clear the cache after dynamic menu changes:

    php bin/console cache:pool:clear app.cache.menu
    

    Or programmatically:

    $this->container->get('chamber_orchestra_menu.cache')->clear();
    
  4. Twig Template Overrides Ensure your custom template extends the base template:

    {% extends '@ChamberOrchestraMenu/menu.html.twig' %}
    

    Override variables like menu_item_classes to modify rendering:

    {% set menu_item_classes = menu_item_classes ~ ' custom-class' %}
    
  5. Performance with Large Menus Use depth_limit in Twig to render only top-level items:

    {{ render_menu('main_menu', { 'depth_limit': 1 }) }}
    

    Or in PHP:

    $menuRenderer->setDepthLimit(1);
    

Debugging Tips

  1. Dump Menu Structure Use the debug command to inspect menus:

    php bin/console debug:menu
    

    Or dump in code:

    dump($menuBuilder->build('main_menu')->toArray());
    
  2. Enable Verbose Logging Add to config/packages/dev/chamber_orchestra_menu.yaml:

    chamber_orchestra_menu:
        debug: true
    
  3. Check Route Matching Verify routes with:

    php bin/console debug:router
    

    Ensure your menu routes exist and are correctly named.

Extension Points

  1. Custom Matchers Implement ChamberOrchestra\MenuBundle\Matcher\MatcherInterface for custom logic (e.g., URL matching):

    class UrlMatcher implements MatcherInterface {
        public function isActive(MenuItem $item, Request $request): bool {
            return str_contains($request->getUri(), $item->getRoute());
        }
    }
    

    Register in config:

    chamber_orchestra_menu:
        matchers:
            url:
                class: App\Matcher\UrlMatcher
    
  2. Custom Item Types Extend MenuItem to add metadata:

    class ExtendedMenuItem extends MenuItem {
        private ?string $customData;
    
        public function setCustomData(string $data): self {
            $this->customData = $data;
            return $this;
        }
    }
    

    Use in Twig:

    {{ menu_item.customData }}
    
  3. Dynamic Item Providers Fetch menu items from a database or API:

    class DatabaseMenuProvider implements MenuProviderInterface {
        public function getItems(string $menuName): array {
            return $entityManager->getRepository(MenuItem::class)
                ->findBy(['menu' => $menuName]);
        }
    }
    

    Register in services.yaml:

    services:
        App\Provider\DatabaseMenuProvider:
            tags:
                - { name: 'chamber_orchestra_menu.provider', menu: 'dynamic_menu' }
    
  4. Override Default Config Use config/packages/override/chamber_orchestra_menu.yaml to override defaults without modifying the bundle’s config.

Configuration Quirks

  1. YAML vs. PHP Config Prefer YAML for static menus; use PHP for dynamic logic:

    // src/Menu/DynamicMenuBuilder.php
    public function build(string $name): Menu {
        $menu = new Menu($name);
        // Add items dynamically...
        return $menu;
    }
    

    Register as a service:

    services:
        App\Menu\DynamicMenuBuilder:
            tags:
                - { name: 'chamber_orchestra_menu.builder', menu: 'dynamic_menu' }
    
  2. Priority of Config Sources Order of precedence:

    1. config/packages/override/chamber_orchestra_menu.yaml
    2. config/packages/chamber_orchestra_menu.yaml
    3. Default
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor