The menu service is designed to help you building and rendering your menus.
It's inspired by sfSympalMenu.
On a component:
// Get a new menu from the service container $this->menu = $this->getService('menu'); // Build the menu $this->menu ->addChild('Home', '@homepage')->end() ->addChild('Contact', 'contact/form')->end() ->addChild('Blog', 'articles/list')->end() ->addChild('Sites') ->addChild('Diem', 'https://diem-project.org')->end() ->addChild('Symfony', 'http://symfony-project.org')->end() ->end();
In the template
// Render the menu echo $menu;
Produced HTML
<ul> <li class="first"><a class="link" href="/">Home</a></li> <li><a class="link" href="/contact-us">Contact us</a></li> <li><a class="link" href="/blog">Blog</a></li> <li class="last">Sites <ul> <li class="first"><a class="link" href="https://diem-project.org">Diem</a></li> <li class="last"><a class="link" href="http://symfony-project.org">Symfony</a></li> </ul> </li> </ul>
This method returns the added child.
$child = $menu->addChild('New child'); // $child is 'New child'
This allows to configure the child in a chainable way:
$child = $menu->addChild('Other child')->secure(true)->liClass('big'); // $child is 'Other child'
To get back the menu, use the end() method.
It's a shortcut to getParent() and simply returns the parent of the current menu.
$menu = $menu->addChild('Other child')->end(); // $menu is the original $menu
This allows to add many childs in a chainable way:
$menu ->addChild('New child')->end() ->addChild('Other child')->secure(true)->liClass('big')->end();
And to create nested menus easily;
$menu ->addChild('Rock bands') // start rock bands menu ->addChild('Led Zeppelin')->end() ->addChild('Deep Purple')->end() ->end(); // end rock bands menu
You can pass a link with the second argument of the addChild method
$menu->addChild('Home', '@homepage');
Or with the link method
$home = $menu->addChild('Home'); $home->link('@homepage');
As the menu service uses Diem Links internally, you can pass both internal or externals uri, records, pages and medias to a menu item.
Exemple: create a product list menu
// Menu item for the product list: use product/list as a link $productListMenu = $menu->addChild('Products', 'product/list'); foreach($products as $product) { // Menu item for a product: use $product as a link $productListMenu->addChild($product->name, $product); }
The label is the text that is displayed in a menu item. It is automatically translated if needed.
// Text label $menuItem->label('Back to homepage'); // HTML label $menuItem->label('<h2>My header label</h2>');
A secured menu item will only be displayed for authenticated users.
$menuItem->secure(true);
A not_authenticated menu item will only be displayed for non authenticated users.
$menuItem->notAuthenticated(true);
If you set credentials to a menu item, it will only be displayed to the users having at least one of the required credentials.
// One credentials $menuItem->credentials('admin'); // Many credentials $menuItem->credentials(array('admin', 'content')); // Same as previous $menuItem->credentials('admin, content');
Defines the class appplied to the ul tag.
$menuItem->ulClass('my_class another_class');
Defines the class appplied to the li tag.
$menuItem->liClass('my_class another_class');
If set to true, an automatic HTML id is added to each li tag, based on the item name.
Defaults to false.
$menuItem->showId(true);
If set to true, the label will automatically be translated.
Defaults to true.
$menuItem->translate(true);
If set to true, the item children are displayed.
Defaults to true.
$menuItem->showChildren(true);
Menu items that target the current page get a "dm_current" class on the li and a tag.
Menu items that target a parent page get a "dm_parent" class on the li and a tag.
Learn more about current and parent classes, and how to change them, on the _link documentation.
// get the menu item parent $parent = $menuItem->getParent(); // get the menu root $root = $menuItem->getRoot(); // get the menu children $children = $menuItem->getChildren(); // get the first or last child $child = $menuItem->getFirstChild(); $child = $menuItem->getLastChild();
If you want to override methods from the dmMenu class, or if you want to move the menu creation to a dedicated class, you may want to use your own menu class.
The getService method accepts a second argument to specify a different class to use.
Create a myMenu class in apps/front/lib/myMenu.php
class myMenu extends dmMenu { // override methods ... // build the menu hierarchy public function build() { $this ->addChild('Home', '@homepage')->end() ->addChild('Contact', 'contact/form')->end() ->addChild('Blog', 'articles/list')->end() ->addChild('Sites') ->addChild('Diem', 'https://diem-project.org')->end() ->addChild('Symfony', 'http://symfony-project.org')->end() ->end(); return $this; } }
Instantiate your menu in a component by specifying your custom class
$this->menu = $this->getService('menu', 'myMenu');
Then render the menu in a partial
echo $menu;
If you need to build automatic recursive menus, use the ->addRecursiveChildren($depth) method. All descendant pages are included and nested in the menu item.
For example, if we have the following page structure:
main/root
main/music
music/rock
music/jazz
main/code
You can write
$menu ->addChild('Home', 'main/root') ->addRecursiveChildren(1);
It will add main/root descendants with a depth of 1. It does the same as:
$menu ->addChild('Home', 'main/root') ->addChild('Music', 'main/music')->end() ->addChild('Code', 'main/code');
And with a depth of 2:
$menu ->addChild('Home', 'main/root') ->addRecursiveChildren(2);
I fetches main/root descendants with a depth of 2, and does the same as:
$menu ->addChild('Home', 'main/root') ->addChild('Music', 'main/music') ->addChild('Rock', 'music/rock')->end() ->addChild('Jazz', 'music/jazz')->end() ->addChild('Code', 'main/code');
The methods moveToFirst and moveToLast allow to move a menu item at the first or last position of its siblings.
With the previous menu example,
$menu['Home']['Music']->moveToLast();
Will place Music before Code.
$menu['Home']['Music']['Jazz']->moveToFirst();
Will place Jazz before Rock.
It is always good to have a sitemap page in your site for SEO and accessibility reasons.
The sitemap_menu service allows you to create one with very few work.
Add a main/sitemap action to your modules.yml file, and refresh the site to create the component and partial.
Then in the component, instantiate the sitemap_menu:
$this->menu = $this->getService('sitemap_menu')->build();
And display it in the partial:
echo $menu;
As the menu service is managed by the Service Container, you can easily change the default class and options for all your site menus:
apps/front/config/dm/services.yml
parameters:
menu.class: myCustomMenu // change class for all menus
menu.options:
translate: false // disable translation for all menus
show_id: true // enable HTML id for all menus
sitemap_menu.class: myCustomSitemapMenu // change class for sitemap menu
Questions and Feedback
If you need support or have a technical question, you can
The documentation is hosted on GitHub. Feel free to submit issues and patches!