add handling of AclCacheInterface
This commit is contained in:
parent
04e7970312
commit
680da9e977
|
@ -33,8 +33,6 @@ use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
|||
/**
|
||||
* An implementation of the AclProviderInterface using Propel ORM.
|
||||
*
|
||||
* @todo Add handling of AclCacheInterface.
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class AclProvider implements AclProviderInterface
|
||||
|
@ -98,6 +96,14 @@ class AclProvider implements AclProviderInterface
|
|||
*/
|
||||
public function findAcl(ObjectIdentityInterface $objectIdentity, array $securityIdentities = array())
|
||||
{
|
||||
$modelObj = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($objectIdentity, $this->connection);
|
||||
if (null !== $this->cache and null !== $modelObj) {
|
||||
$cachedAcl = $this->cache->getFromCacheById($modelObj->getId());
|
||||
if ($cachedAcl instanceof AclInterface) {
|
||||
return $cachedAcl;
|
||||
}
|
||||
}
|
||||
|
||||
$collection = EntryQuery::create()->findByAclIdentity($objectIdentity, $securityIdentities);
|
||||
|
||||
if (0 === count($collection)) {
|
||||
|
@ -120,7 +126,6 @@ class AclProvider implements AclProviderInterface
|
|||
$parentAcl = null;
|
||||
$entriesInherited = true;
|
||||
|
||||
$modelObj = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($objectIdentity, $this->connection);
|
||||
if (null !== $modelObj) {
|
||||
$entriesInherited = $modelObj->getEntriesInheriting();
|
||||
if (null !== $modelObj->getParentObjectIdentityId()) {
|
||||
|
|
|
@ -39,8 +39,6 @@ use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
|||
/**
|
||||
* An implementation of the MutableAclProviderInterface using Propel ORM.
|
||||
*
|
||||
* @todo Add handling of AclCacheInterface.
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class MutableAclProvider extends AclProvider implements MutableAclProviderInterface
|
||||
|
@ -125,11 +123,26 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If caching is enabled, retrieve the (grand-)children of this ACL.
|
||||
* Those will be removed from the cache as well, as their parents do not exist anymore.
|
||||
*/
|
||||
if (null !== $this->cache) {
|
||||
$children = ObjectIdentityQuery::create()->findGrandChildren($objIdentity, $this->connection);
|
||||
}
|
||||
|
||||
// This deletes all object and object-field ACEs, too.
|
||||
$objIdentity->delete($this->connection);
|
||||
|
||||
$this->connection->commit();
|
||||
|
||||
if (null !== $this->cache) {
|
||||
$this->cache->evictFromCacheById($objIdentity->getId());
|
||||
foreach ($children as $eachChild) {
|
||||
$this->cache->evictFromCacheById($eachChild->getId());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
|
@ -151,13 +164,12 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
*/
|
||||
public function updateAcl(MutableAclInterface $acl)
|
||||
{
|
||||
if (!$acl instanceof Acl) {
|
||||
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\PropelBundle\Security\Acl\Domain\Acl only.');
|
||||
if (!$acl instanceof MutableAcl) {
|
||||
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\PropelBundle\Security\Acl\Domain\MutableAcl only.');
|
||||
}
|
||||
|
||||
try {
|
||||
$modelEntries = EntryQuery::create()->findByAclIdentity($acl->getObjectIdentity(), array(), $this->connection);
|
||||
|
||||
$objectIdentity = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($acl->getObjectIdentity(), $this->connection);
|
||||
|
||||
$this->connection->beginTransaction();
|
||||
|
@ -194,6 +206,12 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
|||
|
||||
$this->connection->commit();
|
||||
|
||||
// After successfully committing the transaction, we are good to update the cache.
|
||||
if (null !== $this->cache) {
|
||||
$this->cache->evictFromCacheById($objectIdentity->getId());
|
||||
$this->cache->putInCache($acl);
|
||||
}
|
||||
|
||||
return true;
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (Exception $e) {
|
||||
|
|
|
@ -28,6 +28,7 @@ use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
|||
class AclTestCase extends TestCase
|
||||
{
|
||||
protected $con = null;
|
||||
protected $cache = null;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
|
@ -87,7 +88,7 @@ class AclTestCase extends TestCase
|
|||
|
||||
protected function getAclProvider()
|
||||
{
|
||||
return new MutableAclProvider(new PermissionGrantingStrategy(), $this->con);
|
||||
return new MutableAclProvider(new PermissionGrantingStrategy(), $this->con, $this->cache);
|
||||
}
|
||||
|
||||
protected function getAclObjectIdentity($identifier = 1)
|
||||
|
|
60
Tests/Fixtures/Acl/ArrayCache.php
Normal file
60
Tests/Fixtures/Acl/ArrayCache.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the PropelBundle package.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Tests\Fixtures\Acl;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
|
||||
class ArrayCache implements AclCacheInterface
|
||||
{
|
||||
public $content = array();
|
||||
|
||||
public function evictFromCacheById($primaryKey)
|
||||
{
|
||||
if (isset($this->content[$primaryKey])) {
|
||||
unset($this->content[$primaryKey]);
|
||||
}
|
||||
}
|
||||
|
||||
public function evictFromCacheByIdentity(ObjectIdentityInterface $oid)
|
||||
{
|
||||
// Propel ACL does not make use of those.
|
||||
}
|
||||
|
||||
public function getFromCacheById($primaryKey)
|
||||
{
|
||||
if (isset($this->content[$primaryKey])) {
|
||||
return $this->content[$primaryKey];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getFromCacheByIdentity(ObjectIdentityInterface $oid)
|
||||
{
|
||||
// Propel ACL does not make use of those.
|
||||
}
|
||||
|
||||
public function putInCache(AclInterface $acl)
|
||||
{
|
||||
if (null === $acl->getId()) {
|
||||
throw new \InvalidArgumentException('The given ACL does not have an ID.');
|
||||
}
|
||||
|
||||
$this->content[$acl->getId()] = $acl;
|
||||
}
|
||||
|
||||
public function clearCache()
|
||||
{
|
||||
$this->content = array();
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@
|
|||
namespace Propel\PropelBundle\Tests\Security\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\EntryPeer;
|
||||
|
||||
use Propel\PropelBundle\Security\Acl\AclProvider;
|
||||
|
||||
|
@ -18,6 +20,7 @@ use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
|
|||
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
||||
|
||||
use Propel\PropelBundle\Tests\AclTestCase;
|
||||
use Propel\PropelBundle\Tests\Fixtures\Acl\ArrayCache as AclCache;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
|
@ -218,8 +221,39 @@ class AclProviderTest extends AclTestCase
|
|||
return array($parentObj, $obj, $childObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testFindAclWithEntries
|
||||
*/
|
||||
public function testFindAclReadsFromCache()
|
||||
{
|
||||
$this->cache = new AclCache();
|
||||
|
||||
$obj = $this->createModelObjectIdentity(1);
|
||||
$entry = $this->createEntry();
|
||||
$entry
|
||||
->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity('ROLE_USER')))
|
||||
->setAclClass($obj->getAclClass())
|
||||
->setMask(64)
|
||||
;
|
||||
$obj->addEntry($entry)->save($this->con);
|
||||
|
||||
// Read and put into cache
|
||||
$acl = $this->getAclProvider()->findAcl($this->getAclObjectIdentity(1), array($this->getRoleSecurityIdentity('ROLE_USER')));
|
||||
$this->cache->content[1] = $acl;
|
||||
|
||||
// Change database
|
||||
EntryQuery::create()->update(array(EntryPeer::translateFieldName(EntryPeer::MASK, \BasePeer::TYPE_COLNAME, \BasePeer::TYPE_PHPNAME) => 128), $this->con);
|
||||
$this->assertEquals(0, EntryQuery::create()->filterByMask(64)->count($this->con));
|
||||
|
||||
// Verify cache has been read
|
||||
$cachedAcl = $this->getAclProvider()->findAcl($this->getAclObjectIdentity(1), array($this->getRoleSecurityIdentity('ROLE_USER')));
|
||||
$cachedObjectAces = $cachedAcl->getObjectAces();
|
||||
$this->assertSame($acl, $cachedAcl);
|
||||
$this->assertEquals(64, $cachedObjectAces[0]->getMask());
|
||||
}
|
||||
|
||||
protected function getAclProvider()
|
||||
{
|
||||
return new AclProvider(new PermissionGrantingStrategy(), $this->con);
|
||||
return new AclProvider(new PermissionGrantingStrategy(), $this->con, $this->cache);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ use Propel\PropelBundle\Model\Acl\EntryQuery;
|
|||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
|
||||
use Propel\PropelBundle\Tests\AclTestCase;
|
||||
use Propel\PropelBundle\Tests\Fixtures\Acl\ArrayCache as AclCache;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
|
@ -241,4 +242,78 @@ class MutableAclProviderTest extends AclTestCase
|
|||
$this->getAclProvider()->deleteAcl($this->getAclObjectIdentity(1));
|
||||
$this->assertEquals(0, EntryQuery::create()->count($this->con));
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdateAclCreatesInsertedAces
|
||||
*/
|
||||
public function testUpdateAclWritesCacheOfNewAcl()
|
||||
{
|
||||
$this->cache = new AclCache();
|
||||
$this->assertEmpty($this->cache->content);
|
||||
|
||||
$acl = $this->getAcl();
|
||||
|
||||
$this->assertNotEmpty($this->cache->content);
|
||||
$this->assertSame($acl, $this->cache->content[$acl->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdateAclWritesCacheOfNewAcl
|
||||
*/
|
||||
public function testUpdateAclUpdatesCacheOfAcl()
|
||||
{
|
||||
$this->cache = new AclCache();
|
||||
$acl = $this->getAcl(1);
|
||||
|
||||
$acl->updateObjectAce(0, 128);
|
||||
$this->getAclProvider()->updateAcl($acl);
|
||||
|
||||
$objectAces = $this->cache->content[$acl->getId()]->getObjectAces();
|
||||
$this->assertEquals(128, $objectAces[0]->getMask());
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testUpdateAclWritesCacheOfNewAcl
|
||||
*/
|
||||
public function testDeleteAclEvictsFromCache()
|
||||
{
|
||||
$this->cache = new AclCache();
|
||||
|
||||
$this->getAcl();
|
||||
$this->getAclProvider()->deleteAcl($this->getAclObjectIdentity(1));
|
||||
|
||||
$this->assertEmpty($this->cache->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateAclWithParent
|
||||
* @depends testDeleteAclEvictsFromCache
|
||||
*/
|
||||
public function testDeleteAclEvictsChildrenFromCache()
|
||||
{
|
||||
$this->cache = new AclCache();
|
||||
|
||||
$parentAcl = $this->getAcl(1);
|
||||
$childAcl = $this->getAcl(2);
|
||||
$grandChildAcl = $this->getAcl(3);
|
||||
$grandChildAcl->setParentAcl($childAcl);
|
||||
$childAcl->setParentAcl($parentAcl);
|
||||
|
||||
$this->getAclProvider()->updateAcl($grandChildAcl);
|
||||
$this->getAclProvider()->updateAcl($childAcl);
|
||||
|
||||
$this->assertCount(3, $this->cache->content);
|
||||
|
||||
$this->getAclProvider()->deleteAcl($this->getAclObjectIdentity(1));
|
||||
$this->assertEmpty($this->cache->content);
|
||||
}
|
||||
|
||||
protected function getAcl($identifier = 1)
|
||||
{
|
||||
$acl = $this->getAclProvider()->createAcl($this->getAclObjectIdentity($identifier));
|
||||
$acl->insertObjectAce($this->getRoleSecurityIdentity(), 64);
|
||||
$this->getAclProvider()->updateAcl($acl);
|
||||
|
||||
return $acl;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue