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

Nav Bar Bundle Laravel Package

idci/nav-bar-bundle

A Symfony bundle that adds a configurable navigation bar to your application, letting you define menus, links, and routes in configuration and render them with Twig. Useful for centralizing site navigation and keeping templates free of hardcoded menu markup.

View on GitHub
Deep Wiki
Context7

Getting Started

Before anything else, calibrate: idci/nav-bar-bundle is a Symfony2 bundle, not a Laravel package. There is no service provider, no auto-discovery, no Blade, no config/nav-bar.php merge. A composer require in a Laravel app will either fail dependency resolution (Symfony 2.x constraints vs. Laravel's symfony/* ^6/^7) or drag in an unusable framework generation. Treat the package as a reference implementation to read, not a dependency to install.

Minimal steps if you're evaluating it:

  1. Clone the repo read-only rather than requiring it:
    git clone https://github.com/IDCI-Consulting/NavBarBundle /tmp/navbar
    
  2. Read these first, in order — they are the source of truth, the README on a 0-star Symfony2 bundle is usually stale:
    • Resources/config/services.xml (or .yml) — service IDs, builder/manager class, DI tags.
    • DependencyInjection/IDCINavBarExtension.php — configuration tree, what's actually configurable.
    • The Menu/Item/Builder model classes — the data shape you'll want to copy.
    • Resources/views/*.twig — the recursive render and active-state logic.
  3. If you genuinely must run it (legacy Symfony 2.x app only), register in app/AppKernel.php:
    new IDCI\Bundle\NavBarBundle\IDCINavBarBundle(),
    
    and import the bundle's routing/services per its Resources/config/. Expect to --ignore-platform-reqs or pin PHP ≤7.x.

First use case on a Laravel stack: a two-hour spike where you open the bundle, sketch its item model (label, route/URL, children, active flag, optional role gate), and close the evaluation. The deliverable is a data-shape note, not an integration.

Implementation Patterns

The realistic day-to-day pattern is "borrow the model, build the component." The bundle's value is its menu-tree shape and active-state logic; both port to Laravel in an afternoon.

1. Mirror the item model as value objects.

final class MenuItem
{
    public function __construct(
        public string $label,
        public string $route,          // route name, not URL
        public array $params = [],
        public array $children = [],
        public ?string $gate = null,   // permission gate, checked at render
        public ?string $icon = null,
    ) {}
}

Keep it immutable and build the tree once (in a MenuBuilder service or a config/navigation.php), not per-request ad hoc.

2. Recursive Blade component instead of the Twig recursive include.

{{-- resources/views/components/nav/menu.blade.php --}}
<ul {{ $attributes->merge(['class' => 'nav']) }}>
    @foreach ($items as $item)
        @continue($item->gate && ! auth()->user()?->can($item->gate))
        <li>
            <a href="{{ route($item->route, $item->params) }}"
               @class(['active' => request()->routeIs($item->route)])
               @if($item->children) aria-haspopup="true" aria-expanded="false" @endif>
                {{ $item->label }}
            </a>
            @if($item->children)
                <x-nav.menu :items="$item->children" class="submenu" />
            @endif
        </li>
    @endforeach
</ul>

This is where the Symfony bundle stops helping: it renders markup only, so ARIA, keyboard traversal, and mobile disclosure behavior remain your work.

3. Active-state resolution. The bundle compares the Symfony RequestStack against the item's route. The Laravel equivalent is request()->routeIs($item->route). Note: routeIs supports wildcards (admin.*) — use them for section-level highlighting instead of hand-rolling prefix matching.

4. Inject the menu, don't fetch it in the layout. Use a view composer so the layout stays dumb:

View::composer('layouts.app', fn ($view) =>
    $view->with('nav', app(MenuBuilder::class)->build())
);

5. Authorization at render time, not build time. The bundle's role-gating (if present) resolves during build; porting that to Laravel means evaluating Gate::allows() in the component so the menu reflects session state without rebuilding the tree.

6. Config vs. database — decide explicitly. Static config/navigation.php covers most navs and is cache-friendly. Only reach for a menus/menu_items table if non-engineers must edit menus; then cache the tree and invalidate on write. The bundle implies the dynamic path but doesn't solve CMS permissions or ordering UX — that's a product decision, not a library one.

7. Integration tip — one nav, one component. Replace bespoke nav markup in the layout in a single pass. Mixed hand-written <ul>s and the component drift on active-state handling within a sprint.

Gotchas and Tips

  • The dependency graph is a hard stop, not a nuisance. Symfony2 bundles declare symfony/*: ~2.3; Laravel needs ^6/^7. Composer will resolve-fail or you force it and inherit an unmaintained fork. If you see "conflict with symfony/http-foundation" in CI, that's this, and it isn't fixable with flags.
  • 0 stars / 0 dependents means you are the sole maintainer of anything you adopt or fork. Pin to a commit SHA, vendor-patch in a fork you control, and never rely on an upstream security fix arriving.
  • PHP 8.x is untested territory. Symfony2-era code typically emits deprecations or fatals on 8.1+. If a legacy deployment must keep it alive, pin PHP and treat that pin as a tracked migration blocker.
  • MIT license — forking and adapting is legally clean. That's the only reason this is a "read the source" candidate at all.
  • Read Resources/config/services.xml before the README. Service IDs and the builder class live there; docs are frequently out of sync with code on dead bundles.
  • Twig → Blade is not a find-and-replace. {{ path('route') }} becomes route(), is_granted() becomes @can, and Symfony's app.request becomes request(). The recursive include ({% include ... with {items: child} %}) maps to <x-nav.menu :items="..." />, but escaping and attribute merging differ.
  • Active-state is the most common bug source. After porting, add tests for: exact route match, wildcard section match, and nested item where a parent and a sibling child both match. The bundle's logic usually only handles exact match.
  • Accessibility is the gap the bundle does not close. No focus trapping in disclosure menus, no ARIA state management, no mobile hamburger logic. Budget that work explicitly — it's the larger half of a real nav bar.
  • Extension point to copy, not depend on: if the bundle exposes a custom renderer/item extension interface, mirror the idea (a render() method per item type) in your own component rather than adapting its interfaces.
  • If you ever land on Symfony 4+/5+/6+, use KnpMenuBundle. It's the maintained equivalent and worth naming in the ADR so nobody re-opens this evaluation.
  • Close the loop. Record the composer-conflict check in a throwaway project as the artifact that retires the question; otherwise this package reappears in catalogues and gets re-triaged.
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.
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator