-
Notifications
You must be signed in to change notification settings - Fork 0
Menus
To install it, use composer:
composer require lavary/menus
You can create a menu by using make()
method. Here's a basic usage:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
$menu->add('Home');
$menu->add('About', 'about');
$menu->add('services', 'services');
$menu->add('Contact', 'contact');
});
make()
accepts a name and a callable as the argument. This is where you can define your menu items - by using add()
method.
make()
creates a root node, which is an instance of \Lavary\Menus\Item
itself (This root node does nothing but acts as the parent container for other items ). Then, it calls the passed in callable with the root node object as the argument . Finally, within the callback function, the items are added to the root node.
To define the menu items, we use add()
method. add()
accepts two arguments, the first parameter is the item's title, and the second one is either a simple URL or an array of options. The option's array may contain a number of HTML attributes or a group of settings to define the item's characteristics.
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
// Simple URLs
$menu->add('Home');
$menu->add('About', 'about');
// Using the option array
$menu->add('services', ['url' => 'services', 'class' => 'foo']);
$menu->add('Contact', ['url' => 'contact', 'data-role' => 'item']);
});
Each menu that you create with make()
is stored in $collection
attribute of MenuBuilder
class . This means we can manage several menus (for example, a sidebar or a navigation menu with just one instance of MenuBuilder
class).
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
// First Menu
$builder->make('MyNavBar', function($menu) {
$menu->add('Home');
$menu->add('About', 'about');
$menu->add('services', 'services');
$menu->add('Contact', 'contact');
});
// Second menu
$builder->make('SideBar', function($menu) {
$menu->add('Item', 'item/url');
})
In the preceding code, we have two root nodes MyNavBar
and SideBar
which are stored in property $collection
of $builder
class.
To fetch a certain menu from the collection, you can use get()
:
<?php
// ...
$navbar = $builder->get('MyNavBar')->asUl();
$sidebar = $builder->get('SideBar')->asBootstrap();
// ...
Menus currently provides four rendering method out of the box: asUl()
, asOl()
, asDiv()
, and of course asBootstrap()
.
// ...
echo $menu->get('MyNavBar')->asUl();
Which outputs:
<ul>
<li><a href="">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
Here's another example:
// ...
echo $menu->get('MyNavBar')->asDiv();
Which outputs:
<div>
<div><a href="">Home</a></div>
<div><a href="/about">About</a></div>
<div><a href="/services">Services</a></div>
<div><a href="/contact">Contact</a></div>
</div>
You can also pass an array of attributes to the rendering methods. They will be rendered as HTML attributes for the main container:
// ...
echo $menu->get('myNavBar')->asUl(['data-role' => 'menu', 'class' => 'nav nav-bar navbar-inverse']);
// ...
will output:
<ul data-role="menu" class="nav navbar navbar-inverse">
<li><a href="">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
Note When you're calling
asBootstrap()
, just make sure you have Bootstrap's Javascript and CSS files included in your template.
You can also create your custom renderers by extending the abstract class Lavary\Menus\Renderer\Element
. Then, call render()
method, passing an instance of your custom renderer to it.
<?php
// ...
$customRenderer = new CustomRenderer();
$builder->get('myNavBar')->render($customerRenderer);
// ...
The abstract class forces you to implement a method named render()
.
You can also render a portion of the menu instead of the whole menu:
<?php
// ...
$builder->get('myNavbar')->get('about')->asBootstrap();
The preceding example will only render the children of item About
.
Or you can use the magic "Where" method to query through the items and render the result:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
// First Menu
$builder->make('MyNavBar', function($menu) {
$menu->add('Home')->data('show' => true);
$menu->add('About', 'about')->data('show' => true);
$menu->add('services', 'services')->data('show' => true);
$menu->add('Contact', 'contact')->data('show' => true);
});
$builder->get('MyNavBar')->whereShow(true);
Magic "Where" methods are explained in detail in the next sections.
You define the item's URL by passing the URL as the second argument to the add()
method:
<?php
// ...
$menu->add('About Us', 'about-us');
// ...
Or by specifying the url
option in the options array:
<?php
// ...
$menu->add('About Us', ['url' => 'about-us']);
// ...
Needless to say, items can have sub-items:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
$menu->add('Home');
$menu->add('About', 'about');
$menu->about->add('History', 'about/history');
$menu->about->add('Goals', 'about/goals');
$menu->about->goals->add('Another Item', 'about/goals/another/item')
$menu->about->goals->anotherItem('And another item', 'another/item')
$services = $menu->add('services', 'services');
$services->add('Development', 'about/development');
$services->add('Consultation', 'about/consultation');
$menu->add('Contact', 'contact');
});
As you can see, we can sequentially chain the items to go as deep as required.
This is done by referring to the item's nickname, which is the item's title in camel-case format:
<?php
// ...
$menu->add('What We Do');
// ... and this is how we refer to it:
$menu->whatWeDo->add('Sub item', 'sub/item');
// ...
Since add()
returns the item's object, we can store it in a variable for further reference:
<?php
// ...
$whatWeDo = $menu->add('What We Do');
// ... and this is how we refer to it:
$whatWeDo->add('Sub item', 'sub/item');
// ...
You can also use get()
method to get the item by nickname:
<?php
// ...
$menu->add('What We Do');
// ... and this is how we refer to it:
$menu->get('whatWeDo')->add('Sub item', 'sub/item');
// ...
All these three ways are identical.
Sub-items are stored within $children
property of the parent item.
$children
is an instance of Lavary\Menus\Collection
. You can get it by calling getChildren()
against the parent item.
When you add a new item, a unique ID (which is a random string) is automatically assigned to the item. However, there are times when you need to define them manually. As an example when you're fetching the menu data from a database.
To set the ID manually, you can use setId()
method, passing your desired ID:
<?php
// ...
$menu->add('About', array('url' => 'about'))
->setId('74398247329487')
// ...
Alternatively, you can pass the ID as an element of the options array - when creating the item:
<?php
// ...
$menu->add('About', array('url' => 'about', 'id' => 74398247329487));
// ...
You can get the Item's ID by calling getId()
against the item object.
When you add a new item, a nickname - which is a camel-case form of the item's title - is automatically assigned to the item for reference. For example, an item with the title About Us
would have the nickname aboutUs
.
Again there are times when you have to explicitly define the item's nickname. To do this, you can use setNickname()
<?php
// ...
$menu->add('About', array('url' => 'about'))
->setNickname('about_menu_nickname');
// And use it like you normally would
$menu->get('about_menu_nickname');
// ...
You can also pass the nickname as an element of the options array:
<?php
// ...
$menu->add('About', array('url' => 'about', 'nickname' => 'about_menu_nickname'));
// And use it like you normally would
$menu->item('about_menu_nickname');
// ...
To get the item's nickname, just call getNickname()
as below:
<?php
// ...
$menu->add('About', array('url' => 'about', 'nickname' => 'about_menu_nickname'));
var_dump($menu->about->getNickname());
// ...
You can access defined items throughout the code from inside and outside of the callback function.
As mentioned in the basic examples earlier, we can use item's nickname to refer to it:
<?php
use Lavary\Menus\MenuBuilder;
// ...
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
$menu->add('Home');
// ...
// To refer to the item
$home = $menu->home;
// or
$home = $menu->get('home');
});
Or the get the items from outside the callable:
<?php
use Lavary\Menus\MenuBuilder;
// ...
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
$menu->add('Home');
// ...
});
$home = $builder->get('myNavBar)->home;
// Or
$home = $builder->get('myNavBar)->get('home');
If you're not comfortable with the above methods, you may want to store the item in a variable:
<?php
// ...
$about = $menu->add('About', 'about');
$about->add('Who We Are', 'who-we-are');
$about->add('What We Do', 'what-we-do');
// ...
You can also get an item by ID, by using find()
method:
<?php
// ...
$item = $menu->find(74398247329487)
// ...
To get all the items, you can call getChildren()
against the root node or any item with children - in that case, the children of that item are returned.
Here's an example:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
$menu->add('Home');
$menu->add('About', about');
$menu->add('services', 'services');
$menu->add('Contact', 'contact');
});
$items = $builder->get('MyNavBar')->getChildren();
// ...
getChildren()
returns an instance of \Lavary\Menus\Collection
. Since this collection implements the Arrayable
interface, you can use it with all the PHP's array functions.
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu) {
//...
$menu->add('About', 'about');
$menu->about->add('Goals', 'goals');
$menu->about->add('Portfolio', 'portfolio');
//...
$about_items = $menu->about->getChildren();
});
// ...
You can also search the items by magic "where" methods. These methods consist of a 'where' keyword plus a property or metadata (metadata is explained in detail below).
For example to get an item with parent equal to 12, you can use it like so:
<?php
// ...
$subs = $menu->whereParent(12);
// ...
Or to get item's with a specific meta data:
<?php
// ...
$menu->add('Home', '#')->data('color', 'red');
$menu->add('About', '#')->data('color', 'blue');
$menu->add('Services', '#')->data('color', 'red');
$menu->add('Contact', '#')->data('color', 'green');
// ...
// Fetch all the items with color set to red:
$reds = $menu->whereColor('red');
This method returns an instance of 'Lavary\Menus\Collection'. This class has been adapted from Laravel framework.
Since all the menu items are rendered as HTML elements (like list items or divs), you can define HTML attributes for each item:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
// As you can see, you need to pass the second parameter as an associative array:
$menu->add('Home', array('url' => 'home', 'class' => 'navbar navbar-home', 'id' => 'home'));
$menu->add('About', array('url' => 'about', 'class' => 'navbar navbar-about dropdown'));
$menu->add('services', 'services');
$menu->add('Contact', 'contact');
});
If we call asUl()
on the root node, the result would be something similar to this:
<ul>
<li class="navbar navbar-home" id="home"><a href="http://yourdomain.com">Home</a></li>
<li class="navbar navbar-about dropdown"><a href="http://yourdomain.com/about">About</a></li>
<li><a href="http://yourdomain.com/services">Services</a></li>
<li><a href="http://yourdomain.com/contact">Contact</a></li>
</ul>
It is also possible to set or get HTML attributes after the item has been defined by using attr()
method.
attr()
behaves differently based on the passed arguments. If you call attr()
with one argument, it will return the attribute's value (if it's been already defined).
If you call it with two arguments, It will consider the first and second parameters as a key/value pair and sets a new attribute.
You can also pass an array of attributes to add several of HTML attributes at once (This will override all the existing attributes ).
Lastly, if you call it without any arguments, it will return all the attributes as an associative array.
<?php
//...
$menu->add('About', array('url' => 'about', 'class' => 'about-item'));
echo $menu->about->attr('class'); // output: about-item
$menu->about->attr('class', 'another-class');
echo $menu->about->attr('class'); // output: about-item another-class
$menu->about->attr(array('class' => 'yet-another', 'id' => 'about'));
echo $menu->about->attr('class'); // output: about-item another-class yet-another
echo $menu->about->attr('id'); // output: id
print_r($menu->about->attr());
/* Output
Array
(
[class] => about-item another-class yet-another
[id] => id
)
*/
//...
You can use attr
on a collection of items if you need to add the same arguments to those items at once.
<?php
// ...
$menu->add('About', 'about');
$menu->about->add('Who we are', 'about/who-we-are')->data('color', 'red');
$menu->about->add('What we do', 'about/what-we-do')->data('color', 'red');
// As mentioned earlier getChildren() returns a collection
$menu->about->getChildren()->attr('class', 'about-item');
// or
$menu->about->whereColor('red')->attr('class', 'red-text');
// ...
If you just want to add a class (or classes) to the item's class
attribute, you can use addClass()
method:
<?php
// ...
$menu->about-addClass('another class for about');
// ...
As a result, the passed in value will be appended to the item's existing classes.
All the HTML attributes will go to the wrapping tags (li, div, etc); You might encounter situations when you need to add some HTML attributes to <a>
tags as well.
Each Lavary\Menus\Item
instance has a property which stores an instance of Lavary\Menus\Link
. This object is provided for you to manipulate <a>
tags as an independent entity.
Just like each item, Link
also has an attr()
method, which functions exactly the same as item's:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
// ...
$about = $menu->add('About', ['url' => 'about', 'class' => 'navbar navbar-about dropdown']);
$about->getLink()->attr(['class' => 'dropdown-toggle', 'data-toggle' => 'dropdown']);
// ...
});
If you don't want to use the routing feature provided by the package, you can explicitly set your link's href property:
<?php
// ...
$menu->add('About')->getLink()->href('something/as/url');
// ...
You can insert a separator after each item using divide()
method:
<?php
//...
$menu->add('Item', 'item-url')->divide();
//...
/*
Output as <ul>:
<ul>
...
<li><a href="item-url">Separated Item</a></li>
<li class="divider"></li>
...
</ul>
*/
divide()
also gets an associative array of attributes:
<?php
//...
$menu->add('Separated Item', 'item-url')->divide( array('class' => 'my-divider') );
//...
/*
Output as <ul>:
<ul>
...
<li><a href="item-url">Separated Item</a></li>
<li class="my-divider divider"></li>
...
</ul>
*/
You can append or prepend HTML or plain-text to each item's title after it is defined:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
// ...
$about = $menu->add('About', array('url' => 'about', 'class' => 'navbar navbar-about dropdown'));
$menu->about->appendText(' <b class="caret"></b>')
->prependText('<span class="glyphicon glyphicon-user"></span> ');
// ...
});
The above code will result:
<ul>
...
<li class="navbar navbar-about dropdown">
<a href="about">
<span class="glyphicon glyphicon-user"></span> About <b class="caret"></b>
</a>
</li>
</ul>
You can call prependText
and appendText
on collections return by getChildren()
or magic "where" methods as well.
To insert items as plain text instead of clickable links you can use raw()
:
<?php
// ...
$menu->raw('Item Title', array('class' => 'some-class'));
$menu->add('About', 'about');
$menu->About->raw('Another Plain Text Item')
// ...
/* Output as an unordered list:
<ul>
...
<li class="some-class">Item's Title</li>
<li>
About
<ul>
<li>Another Plain Text Item</li>
</ul>
</li>
...
</ul>
*/
You can manually set a certain menu item as the current item by using setAsCurrent()
method. When an item is set as current, a group of attributes is applied to the item. These attributes - which we call them current-item-attributes - are configurable via the configuration file (more on this below).
<?php
// ...
$menu->add('Home', '#')->setAsCurrent();
// ...
/* Output
...
<li class="active"><a href="#">#</a></li>
...
*/
Menus takes care of this automatically according to the current request URI. It also adds the current-item-attributes to the item's ancestors if the current_affect_parents
option is enabled in the configuration file (more on this in the Configuration section).
Menus uses a matcher class (\Lavary\Menus\Matcher\MatcherInterface
) to determine whether an item is the current one or not.
To do this, it loops through a list of patterns registered with it. Each pattern is a class implementing the interface \Lavary\Menus\Matcher\Pattern\PatternInterface
.
Normally, you don't have to define a matcher when creating menus, but if you want to use your own patterns or configure the existing ones, you should instantiate the matcher and add your custom patterns to it. Then, replace the default matcher with yours, by calling setMatcher()
method.
<?ph
use Lavary\Menus\MenuBuilder;
use Lavary\Menus\Matcher\Matcher;
use Lavary\Menus\Matcher\Pattern\UriPattern;
$builder = new MenuBuilder();
$matcher = new Matcher();
$matcher->addPattern(new YourCustomPattern());
$matcher->addPattern(new UriPattern('current/request/uri'));
$builder->setMatcher($matcher);
$menu->make('MyNavBar', function ($m) {
// ...
});
You can also create your own matcher by implementing Lavary\Menus\Matcher\MatcherInterface
if you need more leverage.
As mentioned earlier, patterns are classes implementing the Lavary\Menus\Matcher\Pattern\PatternInterface
Currently, two pattern classes namely Lavary\Menus\Matcher\Pattern\UriPattern
and Lavary\Menus\Matcher\Pattern\RegexPattern
are provided out of the box.
You can match an item by using Lavary\Menus\Matcher\Pattern\UriPattern
. This pattern matches an item if the item's URI is exactly the same as the current request URI. If you don't specify the current request URI for the pattern, the server value $_SERVER['REQUEST_URI']
will be assumed.
This is the default pattern used by the matcher.
You can also use regular expressions to match a URL. What you need to do is first, create an instance of the matcher and your add several instances of RegexPattern
to it. This is useful when woking with RESTful systems.
<?php
use Lavary\Menus\MenuBuilder;
use Lavary\Menus\Matcher\Matcher;
use Lavary\Menus\Matcher\Pattern\RegexPattern;
$builder = new MenuBuilder();
$matcher = new Matcher();
$matcher->addPattern(new RegexPattern('/\/books\/(.*)/'));
$matcher->addPattern(new RegexPattern('/\/authors\/(.*)/'));
$builder->setMatcher($matcher);
$menu->make('MyNavBar', function ($m) {
// ...
});
According to the preceding code, the matcher has two RegexPattern
patterns to loop through. So all the below URIs are matched by these patterns:
/books/create
/books/12/edit
/authors/create
/authors/12
As a shortcut you can use addRegex
function on the matcher to do the same thing:
<?php
use Lavary\Menus\MenuBuilder;
use Lavary\Menus\Matcher\Matcher;
use Lavary\Menus\Matcher\Pattern\RegexPattern;
$builder = new MenuBuilder();
$matcher = new Matcher();
$matcher->addRegex('/\/books\/(.*)/');
$matcher->addRegex('/\/authors\/(.*)/');
$builder->setMatcher($matcher);
// ...
As mentioned earlier, you can create custom matchers and patterns if the existing ones do not meet your requirements. All you need to do is to implement Lavary\Menus\Matcher\MatcherInterface
and Lavary\Menus\Matcher\Pattern\PatternInterface
interfaces respectively.
One the most amazing things about Menus is menu groups. Sometimes you may need to share attributes between a group of items. Instead of specifying the attributes for each and every item, you may use a menu group.
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
$menu->add('Home', array('url' => 'home', 'class' => 'navbar navbar-home', 'id' => 'home'));
$menu->group(array('style' => 'padding: 0', 'data-role' => 'navigation') function($m) {
$m->add('About', array('url' => 'about', 'class' => 'navbar navbar-about dropdown'));
$m->add('services', 'services');
}
$menu->add('Contact', 'contact');
});
According to the above code, attributes style
and data-role
would be applied to the items defined within the group: About
and Services
.
Here's the output:
<ul>
<li class="navbar navbar-home" id="home"><a href="/home">Home</a></li>
<li style="padding: 0" data-role="navigation" class="navbar navbar-about dropdown"><a href="/about"About</a></li>
<li style="padding: 0" data-role="navigation"><a href="/services">Services</a></li>
<li><a href="/contact">Contact</li>
</ul>
While using the grouping feature, we can add prefixes to be prepended to the items' URL defined within the group
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function ($menu) {
$menu->add('Home', array('url' => 'home', ); // URL: /home
$menu->add('About', array('url' => 'about', 'class' => 'navbar navbar-about dropdown')); // URL: /about
$menu->about->group(array('prefix' => 'about'), function ($about) {
$about->add('Who we are?', 'who-we-are'); // URL: about/who-we-are
$about->add('What we do?', 'what-we-do'); // URL: about/what-we-do
});
$menu->add('Contact', 'contact');
});
The above code outputs:
<ul>
<li><a href="/home">Home</a></li>
<li data-role="navigation" class="navbar navbar-about dropdown"><a href="/about/summary"About</a>
<ul>
<li><a href="/about/who-we-are">Who we are?</a></li>
<li><a href="/about/who-we-are">What we do?</a></li>
</ul>
</li>
<li><a href="services">Services</a></li>
<li><a href="contact">Contact</a></li>
</ul>
Although
group()
method can be called against every item. However, the items defined within the group doesn't have to be children of the item that invokedgroup()
.
Menus supports nested grouping as well. A menu group merges its own attribute with its parent group then shares them between the items defined within it.
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
// ...
$menu->group(['prefix' => 'pages', 'data-info' => 'info'], function($m){
$m->add('About', 'about');
$m->group(['prefix' => 'about', 'data-role' => 'navigation'], function($a){
$a->add('Who we are', 'who-we-are?');
$a->add('What we do?', 'what-we-do');
$a->add('Our Goals', 'our-goals');
});
});
});
If we render it as an unordered list:
<ul>
<li data-info="info">
<a href="/pages/about">About</a>
<ul>
<li data-info="info" data-role="navigation"><a href="/pages/about/who-we-are"></a></li>
<li data-info="info" data-role="navigation"><a href="/pages/about/what-we-do"></a></li>
<li data-info="info" data-role="navigation"><a href="/pages/about/our-goals"></a></li>
</ul>
</li>
</ul>
Important: Please note that if an item or group already has the attribute it will override its parent's. Only the attributes
prefix
andclass
are appended to the parent's value.
You might encounter situations when you need to assign some metadata to each item; This data can be for any use case from item's weight for sorting to item's or required permissions to display the items.
To assign data to an item, you can use data()
method.
If you call data()
with one argument, it will return the data value for you if it's already been defined.
If you call it with two arguments, It will consider the first argument as the key and second argument as the value.
You can also pass an associative array of data if you need to add a group of key/value pairs at once (This will override all the existing metadata).
Lastly, if you call it without any arguments. it will return all data as an array.
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
// ...
$menu->add('Users', array('url' => 'users'))
->data('permission', 'manage_users');
});
Or to access it:
<?php
// ...
var_dump($menu->users->data('permission'))
// ...
A meta data doesn't do anything to the item's behavior on its own, and it won't be rendered in HTML either. It is the developer who decides what to do with it.
You can also call data()
on a collection returned by getChildren()
or magic "where" method, if you need to target a group of items:
<?php
// ...
$menu->add('Users', 'users');
$menu->users->add('New User', 'users/new');
$menu->users->add('Uses', 'users');
// add a meta data to children of Users
$menu->users->children()->data('anything', 'value');
// ...
Meta data can also be used for sorting or filtering the items (More on this below).
You can also cascade this meta to the item's children. You only need to make sure cascade_data
option is enabled in the configuration file (it is enabled by default). As a result, whenever you add a metadata entry to an item, the existing descendants will inherit it.
Very Important Note: The cascading process takes place when a metadata (or a group of metadata) is added to an item with children (if cascading is enabled). This means that it only affects the children created before the cascading process; The children created after the cascading won't inherit the metadata. The reason is that you might want to keep some metadata only for the parent while having the cascading feature enabled as well. So, if cascading is enabled and you want to add some metadata only for the parent, add them before you create any sub-items.
You can filter menu items by a using filter()
method. Filter()
accepts either a key/value pair or a closure.
The following example will filter the items based on metadata show
.
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
$menu->add('Home', 'home')->data('show', true);
$menu->add('About', 'about')->data('show', true);
$menu->add('Services', 'services')->data('show', true);
$menu->add('Portfolio', 'portfolio')->data('show', false);
$menu->add('Contact', 'contact')->data('show', true);
})->filter('show', true);
According to the above code, the value of show
must be true in order to be included in the filter result.
If you want to pass a closure to filter()
, you must return false for the items you want to exclude and true for those you want to keep.
Here's a basic example:
Let's just imagin the User
model can check whether the user has an specific permission or not:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('MyNavBar', function($menu){
// ...
$menu->add('Users', array('url' => 'admin/users'))
->data('permission', 'manage_users');
})->filter(function($item){
if(User::get()->can( $item->data('permission'))) {
return true;
}
return false;
});
As a result, Users
item will be visible to those who has the manage_users
permission. As you probably have noticed we attached the required permission for each item via data()
method.
You can sort the items by using SortBy()
method. sortBy
can sort items by a certain metadata or a user-defined function.
To sort the items based a metadata:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('main', function ($menu) {
$menu->add('About', '#') ->data('order', 2);
$menu->add('Home', '#') ->data('order', 1);
$menu->add('Services', '#') ->data('order', 3);
$menu->add('Contact', '#') ->data('order', 5);
$menu->add('Portfolio', '#') ->data('order', 4);
})->sortBy('order');
In the above code, the items are sorted in ascending order by order
's value.
sortBy()
also receives a second parameter which specifies the ordering type: ascending order asc
and descending order desc
.
The default value is asc
.
You can also sort items by passing a callback function:
<?php
use Lavary\Menus\MenuBuilder;
$builder = new MenuBuilder();
$builder->make('main', function($m){
$m->add('About') ->data('order', 2);
$m->add('Home') ->data('order', 1);
$m->add('Services') ->data('order', 3);
$m->add('Contact') ->data('order', 5);
$m->add('Portfolio') ->data('order', 4);
})->sortBy(function($items) {
// Your sorting algorithm here...
});
The closure takes the root item as argument.
You can adjust the behavior of the menu builder in the provided configuration file (menu.yml
). By default, the configuration file shipped with the package is used by the menu builder. To customize the file, you better make a copy of the configuration file, then customize the settings. You can find the file in the package's root directory.
Here's the list of options you can modify inside the file:
Option Name | Description | Possible Values | Default Value |
---|---|---|---|
cascade_data | If you need descendants of an item to inherit metadata from their parents, make sure this option is enabled | Boolean | True |
auto_activate | Automatically set an item as current if its URI matches to one of the defined patterns | Boolean | True |
current_affect_parents | Set the ancestors of the current item as current | Boolean | True |
active_attributes | A list of attributes to be added to the current item | YAML options | class: active |
active_element | You can choose the HTML element to which you want to add activation attributes (anchor or the wrapping element). |
item or link
|
item |
To use your own configuration file you can create an instance of \Lavary\Menus\Configuration\Configuration
and pass it the MenuBuilder
class constructor.
<?php
use Lavary\Menus\MenuBuilder;
use Lavary\Menus\Configuration\Configuration;
$builder = new MenuBuilder(new Configuration('/path/to/menu.yml'));
// ...
Alternatively you can use setConfiguration()
:
<?php
use Lavary\Menus\MenuBuilder;
use Lavary\Menus\Configuration\Configuration;
$builder = new MenuBuilder();
$builder->setConfiguration(new Configuration('/path/to/menu.yml'));
// ...