One Menu To Rule Them All, (*1)
This bundle is an extension of KnpMenuBundle with which you can add a main menu for the system and this will be filtered depending on user role., (*2)
Features
- The menus can be set from the configuration file
app/config/config.yml
- The menu links are automatically filtered by the rules defined in the firewall
-
JMSSecurityExtraBundle annotations are supported for creating the filter
- Integration with existing menus on your bundle thanks to the @SecureMenu annotation
Requirements
Installation
In order to install the bundle you need to add the dependency in composer.json file., (*3)
//composer.json
"require": {
"zetta/menu-bundle" : "1.1.*"
}
Then you must register the bundle in the kernel of the application., (*4)
// app/AppKernel.php
$bundles = array(
....
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
new Zetta\MenuBundle\ZettaMenuBundle()
It is important that the ZettaMenuBundle statement is after KnpMenuBundle, (*5)
Usage
There are two ways to filter our menus., (*6)
Simple way
If you use the simple method for creating menus, (*7)
// src/Acme/DemoBundle/Menu/Builder.php
namespace Acme\DemoBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
class Builder extends ContainerAware
{
public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('Home', array('route' => 'homepage'));
$menu->addChild('About Me', array(
'route' => 'page_show',
'routeParameters' => array('id' => 42)
));
// ... add more children
return $menu;
}
}
Simply add the annotation Zetta\MenuBundle\Annotation\SecureMenu to the method to filter the items., (*8)
// src/Acme/DemoBundle/Menu/Builder.php
namespace Acme\DemoBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
use Zetta\MenuBundle\Annotation\SecureMenu;
class Builder extends ContainerAware
{
/**
* @SecureMenu
*/
public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('Home', array('route' => 'homepage'));
$menu->addChild('About Me', array(
'route' => 'page_show',
'routeParameters' => array('id' => 42)
));
// ... add more children
return $menu;
}
}
Configuration Method config.yml
We define a menu in the configuration file, (*9)
#app/config/config.yml
zetta_menu:
menus:
admin:
childrenAttributes:
class: 'nav'
children:
dashboard:
label: 'Dashboard'
route: '_welcome'
users:
label: '<i>Users</i>'
uri: '/user/'
extras:
safe_label: true
attributes:
id: 'user'
linkAttributes:
class: 'link'
children:
new:
label: 'New User'
uri: '/user/new'
archive:
label: 'User archive'
uri: '/user/archive'
catalogs:
label: 'Catalogs'
route: 'catalogs'
children:
status:
label: 'Status'
uri: '/status/list'
statistics:
label: 'Stats'
uri: '/admin/stats'
sidebar: #another one ...
children:
sidebar1:
label: "Sidebar 1"
Support KNP Menu Option
* attributes
* linkAttributes
* childrenAttributes
* labelAttributes
* extras
* displayChildren, (*10)
Using the knp twig helper we can print it, (*11)
{{ knp_menu_render('admin') }}
By defailt if no deny rules exists in firewall or annotations the full menu will be printed, (*12)
- Dashboard
- Users
- Catalogs
- Stats
In order to affect the menu render we start to define rules in our firewall, (*13)
#app/config/security.yml
security:
role_hierarchy:
ROLE_MANAGER: ROLE_USER
ROLE_ADMIN: ROLE_MANAGER
...
access_control:
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/user/new, role: ROLE_MANAGER }
- { path: ^/$, role: ROLE_USER }
The system administrator can then see the full menu, however if a user authenticated with ROLE_USER can only view:, (*14)
- Dashboard
- Usuarios
- Catálogos
Annotations
Assuming we have catalogs route defined in routing.yml, (*15)
#app/config/routing.yml
catalogs:
pattern: /catalogs/
defaults: {_controller: ExampleBundle:Catalogs:index}
We add the annotation in the controller's method, (*16)
// src/Acme/ExampleBundle/Controller/CatalogsController.php
use JMS\SecurityExtraBundle\Annotation\Secure;
class CatalogsController{
/**
* @Secure(roles="ROLE_MANAGER")
*/
public function indexAction()
{
// ... blah
}
}
The same user with ROLE_USER will see:, (*17)