Acl Menu Component

Sep 13 2008

By now you’ve got an awesome Acl and Auth controlled app running. However, making navigation menus is a pain with dynamic, and variable permissions. Outside of making menu elements for each type of Aro and including them in your layout, there currently aren’t many options (at least none that I’m aware of). I was faced with this exact problem a while back, and couldn’t find a suitable solution, so I made one. I called it the MenuComponent

What does it do?

This menu component will scan through your application, and generate a list of menu-able actions to be used in menus. When a request is made for a MenuComponent using page, a nested menu array will be created based on the current User’s access permissions. This menu is set to the View and available in your layouts / views. To top it all off, this is done automagically!

What doesn’t it do?

It doesn’t kill the performance of your site for one. It uses a lot of caching to help minimize the hit your application will endure when using dynamically generated menus. It also doesn’t generate menu items for actions that involve id’s, or information from the session. These can be added into the menu’s structure, but it is not done automatically. It also doesn’t make any HTML, how you render these menus is totally up to you.

How do I use it?

At its most basic use, download the MenuComponent and test case and add them to your app. Include the MenuComponent in your AppController or wherever you want to use it and you’re ready to go.

Show Plain Text
  1. var $components = array('Acl', 'Auth', 'Menu');
  2.  

It can obviously get far more complicated. MenuComponent has a number of settings that can be set using “alternate component declarations”/posts/view/cakephp-easter-eggs . Any of the class variables can be set in this manner. Additional configuration related to specific controllers is done in the respective controller. This seems a bit odd, but I chose to do it this way, as it keeps each controller’s contribution to the menu inside that controller. This is in contrast to setting every option for every controller in AppController or wherever you are including the MenuComponent. As this would end up bloated and ugly very quickly.

Using controller options for the MenuComponent

Controller options for the MenuComponent control how the menu is generated for that controller, and nothing else. Each controller’s menuOptions are separate and affect nothing outside of its own actions. $meunOptions provide facilities for aliasing actions, excluding actions and setting the parent menu item of the controllers actions.

Renaming action titles in the menus

Often you don’t want the action name to be the display title in your menu. Setting an alias lets you control the menu’s title.

Show Plain Text
  1. var $menuOptions = array(
  2.     'alias' => array(
  3.         'admin_index' => 'View all Posts',
  4.     ),
  5. );

You basically map the action name to the title text you want to display. Pretty straightforward, right now due to the way the caching is done, you would have to do any i18n work in the views.

Excluding actions from the menu

Excluding actions is done by creating an array of non-private actions, you want to exclude from the menus. You don’t need to specify the following either ‘view’, ‘edit’, ‘delete’, ‘admin_edit’, ‘admin_delete’, ‘admin_edit’, or ‘admin_view’. If you want to change the global list of excluded actions modify MenuComponent::excludeActions. You can also set exclude to ‘‘. Setting exclude to ‘‘ will remove an entire controller, and all of its actions from the generated menus.

Show Plain Text
  1. var $menuOptions = array(
  2.     'exclude' => array('secretStuff');
  3. );
  4. //Or
  5. var $menuOptions = array(
  6.     'exclude' => array('*');
  7. );

Changing the parent element

You can also set the parent menu element for all actions in a controller. This lets you nest a set of controller/actions under an artificial or generated menu.

Show Plain Text
  1. var $menuOptions = array(
  2.     'parent' => 'my-menu-item'
  3. );

This would place all the menus generated for this controller under the menu element with an id of ‘my-menu-item’. Using parent gives you a powerful, and easy way to create a hierarchy in your application’s menu without affecting the actual structure of the application. Menu ids are generated automatically and take the form of $controllerName-$actionName.

Removing the controller element

There are times when you don’t want a menu element for the controller. Normally these occur when using manually added menu elements or specifying $menuOptions['parent'] in these circumstances you can:

Show Plain Text
  1. var $menuOptions = array(
  2.     'controllerButton' => false,
  3. );

This will remove the controller button, and all the actions will become children of whatever $menuOptions['parent'] is set to.

Manually creating menu elements

In addition to automagic generation of menu elements you can manually create menu elements. I’ve used this when, I want to promote a single action to somewhere it normally wouldn’t be able to get to in the menu structure. Or to create menu elements for actions that need an id parameter to work. Creating menu elements looks a bit like this.

Show Plain Text
  1. $this->Menu->addMenu(array(
  2.     'title' => 'My custom menu',
  3.     'parent' => 'my-menu-tree',
  4.     'url' => array(
  5.         'controller' => 'posts',
  6.         'action' => 'new_action',
  7.         'id' => 25
  8.     ),
  9. ));

By using addMenu() you can create menu elements for any path or url on your application. However, the big catch is that all your addMenu() calls must occur before the menus are constructed. This normally occurs automatcally in startup() but can be manually controlled. See the doc blocks for more information regarding that. It is also important to note that if two menu elements exist for the same id, and a user has access to both only the first will show up in the final menu.

Well I hope you find this Component useful and I’d love to hear on how to improve it. You can download the menu component and its related test from my gitHub repository


Comments

Luke on 15/9/08

hey, looks cool – nice you included the manual option…I always end up doign this whenever I try and do a dyanmic menu, and it used to begin with an extra if else, then a case then … serenity etc :)

Natan 3 weeks, 2 days ago

Hi,
it’s very usefull component, but for me it’s lack of some features. I wrote some mods for ex. possibility to set up custom controller’s title by setting $menuOptions[‘ctrlTitle’], because generic just takes ctrl’s name. I think it also needs automagic support for acl public functions to avoid warning if there is no aco’s for them while they are in allowedActions.

Natan 3 weeks, 2 days ago

When it comes about comment from your code “no active session, no menu can be generated”, i think support for for “no session menu” would be not bad, like i said last time we can check up just Auth’s allowedActions and generate menu for public functions.

mark story 3 weeks, 1 day ago

Natan: If check the gitHub, I’ve been working on improvements to the component as I come across the need for them. If you’ve added features or fixed things and would like to share send me an email through my contact form, or fork the code on gitHub, and make a pull request.


Have Something to say?

*
* (Never published, I promise)
* You can use Textile markup, but be reasonable

Recent Artwork

  • CakePHP Test suite icons
  • Shuriken 2
  • Clumsy Penguins
  • Balloon Animals
  • Metal in the air! (vertical)
  • Cleavers