Weave 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 Laravel Package

becklyn/menu

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require becklyn/menu
    

    Add the bundle to config/bundles.php (Symfony 4.4+):

    Becklyn\MenuBundle\BecklynMenuBundle::class => ['all' => true],
    
  2. 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'));
    
  3. Rendering Use Twig to render the menu:

    {{ render(menu) }}
    

    Or pass it directly to a template:

    return $this->render('template.html.twig', ['menu' => $menu]);
    

First Use Case: Simple Navigation Bar

// 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]);
}

Implementation Patterns

Menu Builder Pattern

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()
    ]);

Dynamic Menu Generation

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;
}

Twig Integration

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>

Route-Based Activation

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'
    ])
);

Caching Menus

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
}

Gotchas and Tips

Pitfalls

  1. Route Resolution

    • Ensure routes are properly defined in routes.yaml or routing.yml before using them in menus.
    • Debugging tip: Use {{ dump(menu.items[0].route) }} in Twig to verify route names.
  2. Circular References

    • Avoid adding the same menu item multiple times in nested structures (e.g., parent and child menus). Use unique IDs or route names.
  3. Twig Rendering Quirks

    • If {{ render(menu) }} fails, ensure the BecklynMenuBundle is properly registered in bundles.php and the Twig environment is configured.
  4. Active State Logic

    • The active state is static by default. For dynamic activation (e.g., based on user roles), override the isActive() method in a custom MenuItem class.

Debugging Tips

  • 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
    

Extension Points

  1. 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();
        }
    }
    
  2. 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 }
    
  3. 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]);
        }
    }
    

Configuration Quirks

  • 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>
    
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels