Navigator
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.
Table of Contents
Installation
Via Composer
$ composer require awes-io/navigator
The package will automatically register itself.
Quickstart
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!
Configuration
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()
.
Usage
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.
Some helpful methods
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);
Menu rendering example
// 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
Permissions
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',
],
Testing
The coverage of the package is .
You can run the tests with:
composer test
Contributing
Please see contributing.md for details and a todolist.
Credits
- Alexander Osokin
- Galymzhan Begimov
- [All Contributors][link-contributors]