That’s a very useful article Mark,
I have a question:
how can i fetch only the posts those logged in user is permitted to view them?

my solution is :

SELECT * FROM posts WHERE id IN( SELECT foreign_key FROM acos WHERE id IN( SELECT aco_id FROM aros_acos WHERE aro_id=(SELECT id FROM aros WHERE alias=‘Username’) AND aco_id IN (SELECT id FROM acos WHERE model=‘Post’) AND _read=1 )
)

But, i can’t write that sql query with find or paginate function!
can u help me?!

Vahid Alimohamadi on 12/20/09

Very nice code. I had one problem though, similar to what OstReach mentioned on 25/2/09 – if I have controllers with multiple camel cased words in the name (e.g. UserGroupsController, as per the CakePHP naming conventions), then these were not showing up in the menu. I’d already set up the Auth and ACL on my site as per your tutorials.

The problem is that the AppController::buildAcl method will create a node named UserGroups in the ACO table, but the MenuComponent::constructMenu method generates the ACO names using:

$aco = Inflector::underscore($item[‘url’][‘controller’]);

To be consistent with buildAcl, the ACO name should be camel cased and pluralized, not with underscores. The problem can be corrected by changing the above line in MenuComponent::constructMenu to

$aco = Inflector::camelize($item[‘url’][‘controller’]); $aco = Inflector::pluralize($item[‘url’][‘controller’]);

or simply to

$aco = $item[‘url’][‘controller’];

(because Acl->check does not appear to be case sensitive?)

Tim Taylor on 1/12/10

Oops, that should be

$aco = Inflector::camelize($item[‘url’][‘controller’]); $aco = Inflector::pluralize($aco);

towards the end of the last comment (but as I said, $aco = $item[‘url’][‘controller’] will do just as well).

Tim Taylor on 1/12/10

Could you give more details on how to use addMenu, i.e. how to manually control the construction of the menus when autoLoad is set to false? Where should I put the code that calls addMenu and then manually calls loadCache / constructMenu / writeCache?

Thanks!

Tim Taylor on 2/5/10

I tried to set the ‘weight’ key in the $menuOptions of a controller to change the order in which the controllers are listed in the menu. However, this does not work because generateRawMenus() sets the weight to zero regardless of what is in $menuOptions. This can be fixed by changing line 309 of menu.php from:

‘weight’ => 0

to:

‘weight’ => empty($menuOptions[‘weight’]) ? 0 : $menuOptions[‘weight’]

Tim

Tim Taylor on 2/5/10

I’m new with CakePHP, how do display the menu in view?

Thanks

Davi on 2/25/10

please guys
I need help to install menu with acl (aros,acos)

your code doesn’t work :( maybe you have something wrong
thanks I’m waiting for your response

bessimo on 3/17/10

How do you handle users which are not logged in?
I’ve added some items manually but they are only visible when the user is logged in. Am I missing something?

Greg on 4/9/10

Is it working with cakePHP 1.3?

edge on 6/9/10

Mark, Excellent article+component – just what I needed…

You have a typo/link-missing in the second para of ‘How Do I Use It?’. It looks like ‘alternate component declarations’ should be a link…

Thanks again!

-Craig

Craig on 6/21/10

While using postgresql as the database backend I run into a problem. PostgreSQL is case sensitive throughout and I had to whip up this patch inorder for this component to work:

—- a/controllers/components/menu.php
+++ b/controllers/components/menu.php
-208,7 +208,8 class MenuComponent extends Object { $size = count($this->rawMenus); for ($i = 0; $i < $size; $i++) { $item = $this->rawMenus[$i]; – $aco = Inflector::underscore($item[‘url’][‘controller’]);
+ /* $aco = Inflector::underscore($item[‘url’][‘controller’]); */
+ $aco = $item[‘url’][‘controller’]; if (isset($item[‘url’][‘action’])) { $aco = $this->aclPath . $aco . $this->aclSeparator . $item[‘url’][‘action’]; }
-259,7 +260,8 class MenuComponent extends Object { } $methods = $this->filterMethods($methods, $menuOptions[‘exclude’]);

- $ctrlCamel = Inflector::variable($ctrlName);
+ /* $ctrlCamel = Inflector::variable($ctrlName); */
+ $ctrlCamel = Inflector::pluralize(Inflector::classify($ctrlName)); $ctrlHuman = Inflector::humanize(Inflector::underscore($ctrlCamel)); $methodList = array(); $adminController = false;

Martin Atukunda on 12/3/10

Hi Mark, been reading your articles for some time, but this guide left out one of the most important parts for the beginner who want to manage their ACL.

  • How to render the menu in our views?

I think some are like me, installed your acl_extras and are ready for your menu structure, even declared alright in our $components after installing acl_menu. We can’t seem to get pass rendering the views of it. Any pin-pointing/hint is great. It would be helpful, thanks.

Regards,
Maxim

John Maxim on 1/5/11

Hi,

I was having some problems when I needed to disallow the ‘index’ actions of a controller but allow other actions (like ‘add’). It seems that the top level menu/parent menu is only created if the ‘index’ action of that controller is allowed.

Here’s a hack I did to get around this issue, probably not the best way but it works:

in function constructMenu():

if (!$completeMenu || $this->_rebuildMenus == true) { $this->generateRawMenus(); $menu = array(); $size = count($this->rawMenus);

for ($i = 0; $i < $size; $i++) { $item = $this->rawMenus[$i]; //$aco = Inflector::underscore($item[‘url’][‘controller’]); $aco = $item[‘url’][‘controller’]; if (isset($item[‘url’][‘action’])) { $aco = $this->aclPath . $aco . $this->aclSeparator . $item[‘url’][‘action’]; }
!!!!!NEW STUFF!!!!!! // don’t check the ACO for the Parent/controllerButton menu item. // For when we don’t include the ‘index’ action in our allowed actions. // See the end of the generateRawMenus() function

if ($this->Acl->check($aro, $aco) || empty($item[‘parent’])) {
!!!!!!!!!END NEW STUFF!!!!!!!

if (!isset($menu[$item[‘id’]])) { $menu[$item[‘id’]] = $this->rawMenus[$i]; } } }

and then in function _formatMenu():

foreach ($menu as $item) { $item[‘children’] = array(); $id = $item[‘id’]; $parentId = $item[‘parent’]; if (isset($idMap[$id][‘children’])) { $idMap[$id] = am($item, $idMap[$id]); } else { $idMap[$id] = am($item, array(‘children’ => array())); } if ($parentId) { $idMap[$parentId][‘children’][] =& $idMap[$id]; } else { $out[] =& $idMap[$id]; } }
!!!!!!!!!NEW STUFF!!!!!!! // Remove menus that don’t have any children foreach($out as $key => $value) { if ( empty($out[$key][‘children’])) { unset($out[$key]); } }
!!!!!!END NEW STUFF!!!!!!

—————-

Thanks for the component mark, it’s been really helpful for my project!

Jonathan S on 2/22/11

Lets try that again

code
in constructMenu() :

for ($i = 0; $i < $size; $i++) { $item = $this->rawMenus[$i]; //$aco = Inflector::underscore($item[‘url’][‘controller’]); $aco = $item[‘url’][‘controller’]; if (isset($item[‘url’][‘action’])) { $aco = $this->aclPath . $aco . $this->aclSeparator . $item[‘url’][‘action’]; }

// don’t check the ACO for the Parent/controllerButton menu item. // For when we don’t include the ‘index’ action in our allowed actions. // See the end of the generateRawMenus() function if ($this->Acl->check($aro, $aco) || empty($item[‘parent’])) { if (!isset($menu[$item[‘id’]])) { $menu[$item[‘id’]] = $this->rawMenus[$i]; } } }

in _formatMenu() :

protected function _formatMenu($menu) { $out = $idMap = array(); foreach ($menu as $item) { $item[‘children’] = array(); $id = $item[‘id’]; $parentId = $item[‘parent’]; if (isset($idMap[$id][‘children’])) { $idMap[$id] = am($item, $idMap[$id]); } else { $idMap[$id] = am($item, array(‘children’ => array())); } if ($parentId) { $idMap[$parentId][‘children’][] =& $idMap[$id]; } else { $out[] =& $idMap[$id]; } } // Remove menus that don’t have any children foreach($out as $key => $value) { if ( empty($out[$key][‘children’])) { unset($out[$key]); } }

Jonathan S on 2/22/11

@
constructMenu()

if (!$completeMenu || $this->_rebuildMenus == true) { $this->generateRawMenus(); $menu = array(); $size = count($this->rawMenus);

// Debugger::log(’********ENTERING CONSTRUCT MENU size=’ . $size); for ($i = 0; $i < $size; $i++) { $item = $this->rawMenus[$i]; //$aco = Inflector::underscore($item[‘url’][‘controller’]); $aco = $item[‘url’][‘controller’]; if (isset($item[‘url’][‘action’])) { $aco = $this->aclPath . $aco . $this->aclSeparator . $item[‘url’][‘action’]; } // don’t check the ACO for the Parent/controllerButton menu item. // For when we don’t include the ‘index’ action in our allowed actions. // See the end of the generateRawMenus() function if ($this->Acl->check($aro, $aco) || empty($item[‘parent’])) { if (!isset($menu[$item[‘id’]])) { $menu[$item[‘id’]] = $this->rawMenus[$i]; } } }

_formatMenu() :

foreach ($menu as $item) { $item[‘children’] = array(); $id = $item[‘id’]; $parentId = $item[‘parent’]; if (isset($idMap[$id][‘children’])) { $idMap[$id] = am($item, $idMap[$id]); } else { $idMap[$id] = am($item, array(‘children’ => array())); } if ($parentId) { $idMap[$parentId][‘children’][] =& $idMap[$id]; } else { $out[] =& $idMap[$id]; } } // Remove menus that don’t have any children foreach($out as $key => $value) { if ( empty($out[$key][‘children’])) { unset($out[$key]); } }

@

Jonathan S on 2/22/11

i m trying hard to get it working but no success, i place the menu.php in components folder, in my AppController i called it in $components = array(‘Menu’);

when i try debug($menu) in default.ctp its print a empty array, what i m missing??? can any1 help me?

robson on 2/23/11

Hi, very good website on this niche. I found it on Google. I will surely save it and come back to read it. If you accept a little bit of critique – it needs some iPhone 4S work on the lookpart :)

on 6/7/11

Hello,

I have my aco/aro tables populated with acl_extras.
When I try to run acl_menu I have warnings like:

DbAcl::check() – Failed ARO/ACO node lookup in permissions check.

(Aco part is false)

Any idea what to check?

mehale on 6/13/11