4

I have multiple user roles on my site. Some of the controllers have access restriction based on a user role.
I also have a menu (based on KnpMenuBundle), and I need include only items which are accessible for a logged-in user.

For now I've decided to filter items this way:
1. Add to all of the protected routes a new option roles: i.e. roles: [ROLE_ADMIN, ROLE_MANAGER]
2. During menu building match current user roles with the option.

I've tried to find out whether is there such a functionality in Symfony (I mean role restriction defined in route settings), but I failed to find something similar to that.

So the questions I have are:
1. How to filter menu items based on user roles? (May be is there already a functionality for that?)
If the answer for the previous question is "no", then:
2. how can I build such a filtering on my own? As I've already mentioned I've decided to add a new option in this case, so how to do it the best way?

Vasily
  • 1,858
  • 1
  • 21
  • 34

1 Answers1

3

Maybe you could use my KnpMenu Builder as an example?

namespace AppBundle\Menu;

use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;

class Builder extends ContainerAware
{
    public function mainMenu(FactoryInterface $factory, array $options)
    {
        $sc = $this->container->get('security.context');

        $menu = $factory->createItem('root');
        $menu->setChildrenAttribute('class', 'nav navbar-nav');

        $menu->addChild('About us', array('route' => 'about'));
        $menu->addChild('Contact', array('route' => 'contact'));

        /*
         * before we use isGranted() we have to check if the security is available, otherwise we will receive an exception on the custom error pages. See also
         * http://symfony.com/doc/current/cookbook/controller/error_pages.html#avoiding-exceptions-when-using-security-functions-in-error-templates
         */
        if($sc->getToken())
        {
            $menu->addChild('Members', array('uri' => '#'))
                            ->setAttribute('dropdown', true);

            if($sc->isGranted('IS_AUTHENTICATED_REMEMBERED'))
            {
                $menu['Members']->addChild('My profile', array('route' => 'fos_user_profile_show'));

                if($sc->isGranted('ROLE_ADMIN'))
                {
                    $menu['Members']->addChild('Dashboard', array('route' => 'sonata_admin_dashboard'))
                                    ->setAttribute('divider_append', true);
                }

                $menu['Members']->addChild('Logout', array('route' => 'fos_user_security_logout'));
            }
            else
            {
                $menu['Members']->addChild('Login', array('route' => 'fos_user_security_login'));
                $menu['Members']->addChild('Registration', array('route' => 'fos_user_registration_register')); 
            }
        }

        return $menu;
    }

}
Frank B
  • 3,667
  • 1
  • 16
  • 22
  • OK, thanks for sharing, your method works good =). I will use it if don't find more suitable for my needs. I think it's better keep these role restrictions in one place (e. g. in routing settings), because one should add the same checks in the corresponding controllers (via `isGranted` or `denyAccessUnlessGranted`). And If I manage to add role restrictions in router settings then I can perform such a checks uniformly. – Vasily Nov 09 '15 at 11:24