hailwood/knp-menu-laravel4
Laravel 4 integration for KnpMenu: register KnpMenu in your app, build reusable menu trees, and render navigations in views. Helps organize complex site menus with a familiar builder API and simple configuration.
Installation Add the package via Composer:
composer require hailwood/knp-menu-laravel4
Publish the config file:
php artisan config:publish hailwood/knp-menu-laravel4
Service Provider
Ensure the package is registered in config/app.php under providers:
Hailwood\KnpMenu\KnpMenuServiceProvider::class,
First Menu
Create a menu builder class (e.g., app/Builders/MenuBuilder.php):
namespace App\Builders;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Knp\Menu\MenuItem;
class MenuBuilder
{
public function createMainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->setChildrenAttribute('class', 'nav');
$menu->addChild('Home', ['route' => 'home']);
$menu->addChild('About', ['route' => 'about']);
return $menu;
}
}
Register the Builder
Bind the builder in app/Providers/AppServiceProvider.php:
public function register()
{
$this->app->bind('knp_menu.main', function ($app) {
return new \App\Builders\MenuBuilder();
});
}
Use in a View Inject the menu into a controller or view:
// In a controller
$menu = $this->get('knp_menu.main')->createMainMenu($this->get('knp_menu.factory'), []);
// In a Blade view
@inject('menu', 'knp_menu.main')
{!! $menu->createMainMenu($this->get('knp_menu.factory'), []) !!}
Dynamic Menu Generation Use route parameters or user roles to conditionally render menu items:
$menu->addChild('Admin', ['route' => 'admin.dashboard'])
->setAttribute('class', Auth::check() ? 'active' : '');
Nested Menus Create hierarchical menus with child items:
$productsMenu = $menu->addChild('Products');
$productsMenu->addChild('All Products', ['route' => 'products.index']);
$productsMenu->addChild('Add Product', ['route' => 'products.create']);
Menu Caching
Cache menus for performance (e.g., in AppServiceProvider):
$this->app->singleton('knp_menu.main', function ($app) {
return Cache::remember('main_menu', 3600, function () use ($app) {
return new \App\Builders\MenuBuilder();
});
});
Integration with Blade Directives Create a custom Blade directive for cleaner syntax:
// In AppServiceProvider
Blade::directive('menu', function ($expression) {
return "<?php echo \$this->get('knp_menu.{$expression}')->createMainMenu(\$this->get('knp_menu.factory'), []); ?>";
});
// Usage in Blade
@menu('main')
Menu from Database
Fetch menu items from a database table (e.g., menus):
$menuItems = Menu::where('parent_id', null)->with('children')->get();
foreach ($menuItems as $item) {
$menu->addChild($item->name, ['route' => $item->route])
->setAttribute('class', $item->css_class);
}
$menu->addChild('User Profile', ['route' => ['profile.show', $user->id]]);
$menu->addChild(__('Home'), ['route' => 'home']);
if (Auth::user()->hasRole('admin')) {
$menu->addChild('Admin Panel', ['route' => 'admin']);
}
$menu->setChildrenAttribute('class', 'js-dropdown');
Factory Injection
FactoryInterface can cause errors.$factory to your menu builder methods:
$menu = $factory->createItem('root'); // Correct
// vs.
$menu = new MenuItem('root'); // Wrong
Route Resolution
Route::getRoutes() to ensure routes are loaded:
$menu->addChild('Home', ['route' => 'home'])->setUri(Route::getRoutes()->getByName('home')->getPath());
Circular Dependencies
setLinkAttribute() instead of setUri() for inter-menu links:
$menu->addChild('Parent Menu')->setLinkAttribute('href', route('child_menu'));
Blade Escaping
{{ !! }} or {{{ }}} (deprecated) to output raw HTML:
{!! $menu->render() !!}
Configuration Overrides
config/knp-menu-laravel4.php:
'default_options' => [
'cache' => true,
'max_depth' => 3,
],
Inspect Menu Structure
Use dd($menu->getChildren()) to debug the menu hierarchy:
$menu = $this->get('knp_menu.main')->createMainMenu($this->get('knp_menu.factory'), []);
dd($menu->getChildren());
Check for Missing Routes Ensure all routes referenced in the menu exist:
php artisan route:list
Clear Cache Clear Laravel and KnpMenu caches if menus don’t update:
php artisan cache:clear
php artisan config:clear
Enable Debug Mode
Set 'debug' => true in the config to log menu generation:
'debug' => env('APP_DEBUG', false),
Custom Menu Builders Extend the base builder for reusable logic:
class AdminMenuBuilder extends MenuBuilder
{
public function createAdminMenu(FactoryInterface $factory, array $options)
{
$menu = parent::createMainMenu($factory, $options);
$menu->addChild('Users', ['route' => 'admin.users']);
return $menu;
}
}
Event Listeners Listen to menu generation events (if supported by the package):
// Hypothetical event listener
Event::listen('knp_menu.build', function ($menu, $name) {
if ($name === 'main') {
$menu->addChild('Dynamic Item', ['route' => 'dynamic']);
}
});
Middleware for Menus Use middleware to modify menus based on HTTP context:
// In AppServiceProvider
$this->app->afterResolving('knp_menu.main', function ($builder) {
if (request()->wantsJson()) {
$builder->setJsonOutput(true);
}
});
Testing Menus Test menu generation in PHPUnit:
public function testMainMenu()
{
$factory = $this->app->make('knp_menu.factory');
$menu = $this->app->make('knp_menu.main')->createMainMenu($factory, []);
$this->assertCount(2, $menu->getChildren());
}
How can I help you explore Laravel packages today?