Question

I'm developing an application on ZF.

I've faced a huge unsolvable problem - ZEND_Acl

It's unsolvable for me because every article that I found doesn't relate to MODULE based applications.

lately I discovered packtpub article that described using ACL in models

But it looks complex, complicated and not the very one I've been looking for.

It has StoreFront - and everything goes in there, in my case I have everything separated into modules.

I've seen ACL implementation techniques in many other sources as well as documentation.

I can't figure out how to solve and where to start (and actually HOW TO) developing/structuring my ACL implementation.

my application looks like this:

application/ 
       configs/
       layouts/
               master.phtml
               admin.phtml
       modules/
               users/
                    controllers/
                                adminController
                                indexContoller
                    models/
                    views/
               blog/
                    controllers/
                                adminController
                                indexController
                    models/
                    views/
               orders/
                    controllers/
                                adminController
                                indexController
                    models/
                    views/

as you can see I have admin functionality in adminControllers and frontend functionality in indexControllers.

the idea of having adminControllers and views inside of modules is to have decentralized architecture of modules instead of creating separate module for admin.

now I want to implement ACL for my application.

normally I would have admins - superadmin, Editor, Publisher -- admins that will access all adminControllers but each it's action and for sure Users can't access adminControllers.

and users - visitor, registered, paid so the hierarchy would look smth like this:

$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('visitor')); 
$acl->addRole(new Zend_Acl_Role('registered'), 'visitor');
$acl->addRole(new Zend_Acl_Role('paid'), 'registered');
$acl->addRole(new Zend_Acl_Role('publisher'), 'paid');
$acl->addRole(new Zend_Acl_Role('editor'), 'publisher');
$acl->addRole(new Zend_Acl_Role('superadmin'), 'editor');  

this hierarchy would be available cross-application.

the goal is to write write permissions and resources inside each module, this way I would avoid of having trash in my ACL document when some module doesn't exist for a specific project.

I haven't yet tested the approach of Alexander Romanenko's tutorials on YouTube, but when developing ACL he is loading ACL from the FrontController Plugin - what would be the approach in my case?

And when implementing ACL I have to take into consideration ACL Dynamic Assertions for sure for the future. And moments like "VISITORS" can't post comments, and REGISTERED users can't see PAID articles in the blog.

Maybe you can help me out to integrate ACL into my project, maybe you know good resources where to find HOW TO's and to follow the instructions.

EDIT

The Controller Plugin that will have preDispatch() of ACL will be for each module (in this case USERS) (right?)

I tried to auto load plugin in Module's (USERS) Bootstrap:

$plugin = Zend_Controller_Front::getInstance();
$plugin->registerPlugin(new Users_Plugin_AccessCheck());

But it seems like it takes this plugin for entire application and gives error:

Fatal error: Uncaught exception 'Zend_Session_Exception' with message 'Session must be started before any output has been sent to the browser; output started in H:\Server\xampp\htdocs\c2g\application\modules\users\plugins\AccessCheck.php/6' in H:\Server\xampp\htdocs\c2g\library\Zend\Session.php:451 Stack trace: #0 ... So on

I think this is because plugin is loaded twice. But this keeps happening on every page except the very module (USERS) itself.

Was it helpful?

Solution

I use a similar structure in one of my applications, so hopefully I can point you in the right direction. The way I have it setup is:

  • Roles are initialized in my main application bootstrap (this the code you included in your question), store the Zend_Acl object in the registry for easy access elsewhere
  • Each module bootstrap sets up its own ACL resources and defines which roles can access what
  • The ACL checking is done using a controller plugin.

Resources names are just arbitrary strings, so as long as you stick to a convention, you can perform the ACL checks automatically in your plugin. For example say all your want is a resource for the index and admin controller for each module. In each module bootstrap you have something like this:

protected function _initAcl()
{
    $acl = Zend_Registry::get('acl');

    $frontendResource = new Zend_Acl_Resource('users');
    $adminResource = new Zend_Acl_Resource('users-admin');

    $acl->addResource($frontendResource);
    $acl->addResource($adminResource);

    // allow everyone frontend access
    $acl->allow('visitor', $frontendResource);

    // admins only for admin access
    $acl->allow('superadmin', $adminResource);
}

Then in your ACL controller plugin, work out the resource name by inspecting the request object and perform the check:

public function preDispatch(Zend_Controller_Request_Abstract $request)
{
    $acl = Zend_Registry::get('acl');

    $currentResource = $request->getModuleName().'-'.$request->getControllerName();
    if ($acl->has($currentResource) && !$acl->isAllowed($user->role, $currentResource)) {
        // permissions error
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top