One Menu To Rule Them All
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.
- 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
- PHP >=5.4
- KnpMenuBundle
- KnpMenu
- JMSSecurityExtraBundle
In order to install the bundle you need to add the dependency in composer.json file.
//composer.json
"require": {
"zetta/menu-bundle" : "1.1.*"
}Then you must register the bundle in the kernel of the application.
// app/AppKernel.php
$bundles = array(
....
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
new Zetta\MenuBundle\ZettaMenuBundle()It is important that the ZettaMenuBundle statement is after KnpMenuBundle
There are two ways to filter our menus.
If you use the simple method for creating menus
// 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.
// 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;
}
}We define a menu in the configuration file
#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
Using the knp twig helper we can print it
{{ knp_menu_render('admin') }}By defailt if no deny rules exists in firewall or annotations the full menu will be printed
- Dashboard
- Users
- New User
- User Archive
- Catalogs
- Status
- Stats
In order to affect the menu render we start to define rules in our firewall
#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:
- Dashboard
- Usuarios
- Usuarios históricos
- Catálogos
- Status
Assuming we have catalogs route defined in routing.yml
#app/config/routing.yml
catalogs:
pattern: /catalogs/
defaults: {_controller: ExampleBundle:Catalogs:index}We add the annotation in the controller's method
// 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:
- Dashboard
- Usuarios
- Usuarios históricos