Recently I have been playing around with Rediska and Zend_Acl looking at different ways to store the lists and manipulate them so I put together a few of my scribbles to share.
Requirements:
This basic demonstrate support for multiple containers, utilizes a singleton for creation of each container. The creation of nonexistent acl containers within redis is delegated to the Rediska_Key::getOrSetValue method for initialization of the redis key being requested. This method uses the Acls name (‘BugsService’) through ReflectionClass to locate the proper creation controls.
<?php
class RediskaAcl extends Zend_Acl
{
/**
*
* @var Rediska_Key
*/
protected $_redis;
/**
*
* @var string
*/
protected $_key;
/**
*
* @param string $key
*/
public function __construct($key)
{
$this->_key = $key;
}
/**
*
*/
protected function _getRedis()
{
if(!$this->_redis){
$redis = new Rediska_Key($this->_key);
$this->setRedis($redis);
}
return $this->_redis;
}
/**
*
* @param Rediska_Key_Abstract $redis
*/
public function setRedis(Rediska_Key_Abstract $redis)
{
$this->_redis = $redis;
}
/**
*
* @param Zend_Acl $acl
*/
public function saveAcl()
{
$this->_getRedis()->setValue($this);
}
/**
* Rediska_Key::getOrSetValue checks if the keys exists if not it uses the
* provided object and executes the chained method to set the value returned
* by the method
* @param string $key
*/
public function getAcl($key)
{
$reflection = new ReflectionClass('Model_'.$key.'Acl');
return $this->_getRedis()->getOrSetValue($reflection->newInstance())
->getAcl();
}
}
SomeAclService::getInstance($aclName)
returns the RediskaAcl
container with name: $aclName
.
<?php
class SomeAclService
{
/**
*
* Enter description here ...
* @var unknown_type
*/
private static $_instance = array();
/**
*
* Enforce singleton and prevent access to constructor.
*/
private function __construct()
{
}
/**
*
* prevent cloning
*/
private function __clone()
{
}
/**
* provide name of an acl container being requested
* @return RediskaAcl
*/
public static function getInstance($key)
{
if(
!array_key_exists($key, self::$_instance) ||
!self::$_instance[$key] instanceof RediskaAcl
){
$instance = new RediskaAcl($key);
$acl = $instance->getAcl($key);
if($acl instanceof RediskaAcl){
self::$_instance[$key] = $acl;
}
}
return self::$_instance[$key];
}
}
RediskaAcl
extends Zend_Acl
, providing methods:
getAcl()
returns the object, creating the object and saving to the redis namespace if it does not exist
setAcl()
, allows a manual save of the current Acl in the event it is modified.
setRedis()
allows for run time Rediska instance configuration.
Model_BugsServiceAcl
provides the mechanisms by which first time creation of the Acl is realized, this may be a Mapper to the database models that would generate the Acl and return the RediskaAcl
object that is then saved to the redis namespace.
<?php
/**
*
* This could be a mechanism that builds acl lists from the database or file
* based storage.
* @author zircote
*
*/
class Model_BugsServiceAcl
{
public function getAcl()
{
$acl = new RediskaAcl('BugsService');
$acl->removeRoleAll()->removeAll();
$acl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('member'),'guest')
->addRole(new Zend_Acl_Role('admin'), 'member')
->addRole(new Zend_Acl_Role('someAdmin'), 'admin')
->addRole(new Zend_Acl_Role('someMember'), 'member')
->addRole(new Zend_Acl_Role('someGuest'), 'guest')
->addResource(new Zend_Acl_Resource('someMemberResource'))
->addResource(new Zend_Acl_Resource('someGuestResource'))
->addResource(new Zend_Acl_Resource('someAdminResource'))
->deny()
->allow('guest', 'someGuestResource')
->allow('member', 'someMemberResource')
->allow('admin', 'someAdminResource');
return $acl;
}
}
RedisAclTest
demonstrates the use and verification of proper functionality of the Acl roles and resources.
<?php
require_once 'Rediska.php';
require_once '../example/RediskaAcl.php';
require_once '../example/SomeAclService.php';
require_once '../example/model/BugsServiceAcl.php';
require_once 'PHPUnit/Framework/TestCase.php';
/**
* RediskaAcl test case.
*/
class RediskaAclTest extends PHPUnit_Framework_TestCase
{
/**
* @var RediskaAcl
*/
private $RediskaAcl;
/**
* Prepares the environment before running a test.
*/
protected function setUp ()
{
parent::setUp();
$rediska = new Rediska();
$this->RediskaAcl = SomeAclService::getInstance('BugsService');
}
/**
* Cleans up the environment after running a test.
*/
protected function tearDown ()
{
$this->RediskaAcl = null;
parent::tearDown();
}
/**
*
*/
public function testAssertions()
{
$acl = $this->RediskaAcl;
$this->assertTrue($acl->isAllowed('someGuest', 'someGuestResource'));
$this->assertTrue($acl->isAllowed('someAdmin', 'someAdminResource'));
$this->assertTrue($acl->isAllowed('someMember', 'someMemberResource'));
/* verify proper denial */
$this->assertFalse($acl->isAllowed('someGuest', 'someAdminResource'));
$this->assertFalse($acl->isAllowed('someGuest', 'someAdminResource'));
$this->assertFalse($acl->isAllowed('someGuest', 'someMemberResource'));
$this->assertFalse($acl->isAllowed('someMember', 'someAdminResource'));
}
}
Finally a short example of runtime usage
<?php
$rediska = new Rediska();
echo SomeAclService::getInstance('BugsService')
->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';