KnpLabs / KnpMenuBundle

Object Oriented menus for your Symfony project.
http://knplabs.com
MIT License
1.4k stars 203 forks source link

Add access permissions for showing decisions #51

Closed nfx closed 12 years ago

nfx commented 13 years ago

Goal

Possible solution

stof commented 13 years ago

IMO the good solution would be to check the role when creating the menu instead of adding such a dependency in the MenuItem object:


<?php

$menu = new MenuItem('Courses');
if ($securityContext->isGranted('ROLE_CREATE_COURSE') {
    $menu->addChild('Create new', $router->generate('create_course'));
}
if ($securityContext->isGranted('ROLE_EDIT_OWN_COURSE') {
    $menu->addChild('Edit own', $router->generate('edit_own_courses'));
}
$mainMenu->addChild($menu);

Such a way to do gives far more flexibility about the checks you can perform.

docteurklein commented 13 years ago

Third solution:

create a MenuItem subclass that handles this special case:

You could add a condition on url generation based on securityContext->hasRole method and generate route only if granted.

This logic could be put in a addChildIf method for example.

Is this a good idea?

nfx commented 13 years ago

docteurklein, yes, addChildIf or addSecureChild could help. Maybe adding some Renderer\SecureRenderer could help?

docteurklein commented 13 years ago

the same default renderer can be used.

If you don't provide a url, then only the label will be displayed, without link. You could also decide not to show anything at all if credentials are not matched.

zerkalica commented 13 years ago

I wrote MillwrightMenuBundle which extends base functionality of KnpMenuBundle and adds configuration, route, translation and security context support.

  1. MenuItem knowns about menu context: securityContext, router and translation
  2. I used setShow/getShow methods for control menu item render
  3. All menus are stored in config
  4. Loaded menu items can be modified (route and translation params)
  5. All options of parent menu item inherited as defaults in child items
  6. Configuration is simple - only menu item name is required: in this case name property used for route and label

Configuration example and options descriptions in Resources/doc/index.md

https://github.com/zerkalica/MillwrightMenuBundle

stof commented 12 years ago

Given the new architecture of the bundle, the cleanest way is probably to do some checks in the builder of the menu using the security context (injected as a dependency when using a service, or retrieved from the container when using the alias provider). Doing these checks in the renderer seems weird to me.

jared-fraser commented 12 years ago

Confirmed passing in the security context via the service is a nicer way to doing things.

arguments: ["@knp_menu.factory", "@security.context"]

Then in your MenuBuilder

public function __construct(FactoryInterface $factory, SecurityContextInterface $securityContext)
{
    $this->factory = $factory;
    $this->securityContext = $securityContext;
}

public function createMainMenu(Request $request)
{
    $menu = $this->factory->createItem('root');
    $menu->setCurrentUri($request->getRequestUri());

    $menu->addChild('Home', array('route' => '_welcome'));
    if ($this->securityContext->isGranted('ROLE_ADMIN') !== false) {
        $menu->addChild('Admin', array('route' => 'sonata_admin_dashboard'));
    }
}