Zend_Acl + Zend_Auth + Zend_Controller_Plugin = HAPPY!
Ok, so after playing around with Zend_Acl for what seems like forever I’ve finally cracked what feels like the perfect marriage between Zend_Acl, Zend_Auth and an application.
You may ask yourself, why the fuck is it so hard? The simple answer is this…
Zend_Aclwas designed in such a way that it does not require any particular backend technology such as a database or cache server for storage of the ACL data. Its complete PHP implementation enables customized administration tools to be built uponZend_Aclwith relative ease and flexibility.
Ease and flexibility my arse! This is the reason quite a few Zend Developers are just pulling their hair out day in day out. The documentation at zendframework.com by far is the most confusing I’ve ever seen and quite a bit of it is outdated. It’s actually easier reading through the API documentation and trolling through the code than it is reading this stuff. I truelly feel sorry for people using ZF in anything less than ZendStudio or an IDE without the code completion. Authentication and Authorisation are pretty key aspect of any application, if they made it simple for people to set up they wouldn’t need a 2 paragraph section saying how to store the data by serializing it. Any way, rant over!
The Solution
There are many ways to store the ACL data for persistence, but I think that’s the problem. As soon as you hear the words store and persistance the bells and whistles in your head are screaming at you telling you to store it in a database just like in CakePHP. For months I’d been trying to work out a way to do this until last night.
Why not put this in the application configuration (application.ini)? This is application configuration after all! What’s the point in taking a hit on your database every time you want to check authorisation and then having to write caching code to counteract that? It’s counterproductive and not cost effective (thanks Kennedy stole your phrase).
We can then read the configuration from ini file which contains all of our Resources and Roles.
To begin I set my self some conditions:
- Whatever the solution is, it has to be decoupled from the rest of the application apart from the models used for the user obviously.
- It has to be piss easy to implement
- It has to be so easy to implement my mum could do it!
Sorry for my bad English.
Init “$acl = new Application_Acl($config);” in method preDispatch bad good idea.
Because, when you call Zend_Controller_Action::_forward, you init your Acl several.
Init in the method __construct from class your Plugin
Just wanted to drop you a line to say thanks for helping me wrap my brain around this. I was struggling with exactly the same criteria as you (especially the piss easy bit), and this post helped me finally nail it.
good work!
Interesting article, however I found that this prevents my 404 page from working.
So if i type in /foo (a non-existing controller) it just redirects to the login page.
Any ideas?
Ben
Never mind I figured this out.
In the example code if a resource is not found the resource is set to null. In my circumstance this is the 404 condition.
So rather than setting the resource to null, i throw an exception which is handled by the error controller.
Anyhew, thanks for the above very useful.
It’s no problem, I’m glad this helped demystify this somewhat! I’ve amended the article so that it throws an exception now.
There is also an easier way to access your application.ini file through the bootstrap!
Right now I have the acl in it’s own config. I load the config and the model in the bootstrap then save the acl model to the registry so I can use it in my Access plugin.
I need to set up caching for this since I think parsing this file all the time might be a performance hit. Especially when it gets big.
The odd thing is, I did not think setting a model would work in the boostrap because it is invoked before the app knows about the models (at least that is what I thought).
protected function _initAcl() {
$aclConfig = new Zend_Config_Ini(APPLICATION_PATH . ‘/configs/acl.ini’, APPLICATION_ENV);
$aclModel = new Model_Acl($aclConfig);
Zend_Registry::set(‘aclModel’, $aclModel);
}
To be safe I think I will move the model instantiation and caching to my Access plugin. This will also keep all the acl stuff more centrally located.
Fun! fun!
You have a small typo in /library/Application/Acl.php on line 42, it should be if($permissions == ‘allow’) instead of if($permissions = ‘allow’)
He there
first of all thnx for this one it made several things clear
but i still have a question, how can you combine this with zend_navigation?
I need some links be hidden if the user is ‘guest’
thnx !
Thanks for this.
There is also another small typo. In /library/Application/Controller/Plugin/Acl.php you can remove the print_r on line 17.
KUTGW!
Hey.
Thanks for this great tut.
I’m just having a small issue.
Once the AclPlugin is registered to the front controller, I’m getting this error:
Fatal error: Cannot redeclare class Application_Acl in /Applications/MAMP/htdocs/…/library/Application/Acl.php on line 58
Any idea why?
Thanks.
Nevermind I found the solution.
What about redirecting a denied role to a denied action in the error controller instead of redirecting to the login page?
You must also add in your application.ini:
acl.resources.allow.user.logout = guest
Withou this, you can’t logout.
nail designs…
[...]Zend_Acl + Zend_Auth + Zend_Controller_Plugin = HAPPY![...]…