Laravel package that can easily create navigation menus of any complexity. With support for routing, permissions, sorting, rendering depth, active items marking and element searching.
Via Composer
$ composer require awes-io/navigator
The package will automatically register itself.
Let's firstly create basic navigation, which covers most of the use cases.
Create navigation configuration file:
// config/navigation.php
return [
[
'name' => 'Projects',
'route' => 'projects.index', // route must exist or item will be hidden
'children' =>
[
[
'name' => 'New projects',
'link' => '/projects/new', // you can use direct links
]
]
],
[
'name' => 'Packages',
'route' => 'packages.index',
]
];
Next, let's build our menu somewhere in the controller and pass it to a view:
$menu = buildMenu(config('navigation'));
return view('menu', compact('menu'));
And finally implement basic rendering logic:
// menu.blade.php
@foreach($menu as $item)
<ul>
<li>
@if($item->link())
<a href="{{$item->link()}}">
@if($item->isActive()) ACTIVE @endif {{$item->name}}
</a>
@else
{{$item->name}}
@endif
</li>
@if($item->hasChildren())
@include('menu', ['menu' => $item->children()])
@endif
</ul>
@endforeach
That's all that simple!
You can publish the config file:
php artisan vendor:publish --provider="AwesIO\Navigator\NavigatorServiceProvider" --tag="config"
And rename any options keys, which are used to get respective data from the menu config:
// navigator.php config
'keys' => [
'depth' => 'depth', // rendering depth
'order' => 'order', // ordering by parameter
'children' => 'children', // sub menu items
'route' => 'route', // route name
'link' => 'link', // item link url
'title' => 'name', // item title
'attr' => 'attr', // additional item attributes
],
As well as use alternative menu settings for parsing and rendering:
// navigator.php config
'keys' => [
...
'children' => 'other-children', // alternative sub menu items
...
],
// navigation.php
'menu' => [
[
...
'children' => [
...
'other-children' => [
...
]
Navigator::buildMenu(config('navigation.menu')); // will now parse menu using 'other-children'
You can achieve the same effect dynamically, via mappings mentioned above:
$menu = buildMenu(config('navigation.menu'), [], ['children' => 'other-children']);
Note that we now use the global helper method buildMenu()
.
use AwesIO\Navigator\Facades\Navigator;
$menu = Navigator::buildMenu(config('navigation.menu'), ['depth' => 2], [], function ($item) {
$item->put('meta', $item->get('title') . ' / ' . $item->get('link'));
});
// using helper, rendering depth set via config as a second parameter
$menu = buildMenu(config('navigation.menu'), ['depth' => 2], [], function ($item) {});
The first parameter is the menu config in the form of an array:
// navigation.php
return [
'menu' => [
[
'title' => 'Products', // menu item's title
'route' => 'products.index', // route name for URL generation
'order' => 1, // parameter to determine the order
'depth' => 1, // depth for the recursive generation of descendants
'children' =>
[
[
'id' => 1, // custom id which overwrites auto-generated one
'title' => 'Catalog',
'link' => 'products/catalog', // explicit relative path for link URL
],
[
'title' => 'Support',
'route' => 'products.support'
]
]
],
[
'title' => 'Contact us',
'route' => 'contacts',
'order' => 2,
],
]
];
Second is config, the third one is mappings for configuration parameters (described above), last is a callback, which will be applied to each menu item.
Determine if the node has any children and retrieve them:
$menu->hasChildren();
$menu->children();
Get a link URL for a node:
$menu->link();
Determine if a node is currently selected and active:
$menu->isActive();
Get a currently active node and its id:
$menu->getActive();
$menu->getActiveId();
Find a node by its id:
$menu->findById($id);
// somewhere in a controller
$menu = Navigator::buildMenu(config('navigation.menu'));
return view('view', compact('menu'));
// view.blade.php
@extends('main')
@section('content')
@include('menu', ['menu' => $menu])
@endsection
// menu.blade.php
@foreach($menu as $item)
<ul>
<li>
@if($item->link())
<a href="{{$item->link()}}">{{$item->title}}</a>
@else
{{$item->title}}
@endif
</li>
@if($item->hasChildren())
@include('menu', ['menu' => $item->children()])
@endif
</ul>
@endforeach
If the user is not authorized to access some of the menu routes, they'll be automatically hidden based on existing permissions:
Route::group(['middleware' => ['can:manage users']], function () {
Route::get('/', 'RoleController@index')->name('admin.roles.index');
});
// will be excluded from the menu for non-admin users
[
'name' => __('navigation.security'),
'icon' => 'twousers',
'route' => 'admin.roles.index',
],
The coverage of the package is .
You can run the tests with:
composer test
Please see contributing.md for details and a todolist.
- Alexander Osokin
- Galymzhan Begimov
- [All Contributors][link-contributors]