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.
|
* An implementation of the AclProviderInterface using Propel ORM.
|
||||||
*
|
*
|
||||||
* @todo Add handling of AclCacheInterface.
|
|
||||||
*
|
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
*/
|
*/
|
||||||
class AclProvider implements AclProviderInterface
|
class AclProvider implements AclProviderInterface
|
||||||
|
@ -98,6 +96,14 @@ class AclProvider implements AclProviderInterface
|
||||||
*/
|
*/
|
||||||
public function findAcl(ObjectIdentityInterface $objectIdentity, array $securityIdentities = array())
|
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);
|
$collection = EntryQuery::create()->findByAclIdentity($objectIdentity, $securityIdentities);
|
||||||
|
|
||||||
if (0 === count($collection)) {
|
if (0 === count($collection)) {
|
||||||
|
@ -120,7 +126,6 @@ class AclProvider implements AclProviderInterface
|
||||||
$parentAcl = null;
|
$parentAcl = null;
|
||||||
$entriesInherited = true;
|
$entriesInherited = true;
|
||||||
|
|
||||||
$modelObj = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($objectIdentity, $this->connection);
|
|
||||||
if (null !== $modelObj) {
|
if (null !== $modelObj) {
|
||||||
$entriesInherited = $modelObj->getEntriesInheriting();
|
$entriesInherited = $modelObj->getEntriesInheriting();
|
||||||
if (null !== $modelObj->getParentObjectIdentityId()) {
|
if (null !== $modelObj->getParentObjectIdentityId()) {
|
||||||
|
|
|
@ -39,8 +39,6 @@ use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||||
/**
|
/**
|
||||||
* An implementation of the MutableAclProviderInterface using Propel ORM.
|
* An implementation of the MutableAclProviderInterface using Propel ORM.
|
||||||
*
|
*
|
||||||
* @todo Add handling of AclCacheInterface.
|
|
||||||
*
|
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
*/
|
*/
|
||||||
class MutableAclProvider extends AclProvider implements MutableAclProviderInterface
|
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.
|
// This deletes all object and object-field ACEs, too.
|
||||||
$objIdentity->delete($this->connection);
|
$objIdentity->delete($this->connection);
|
||||||
|
|
||||||
$this->connection->commit();
|
$this->connection->commit();
|
||||||
|
|
||||||
|
if (null !== $this->cache) {
|
||||||
|
$this->cache->evictFromCacheById($objIdentity->getId());
|
||||||
|
foreach ($children as $eachChild) {
|
||||||
|
$this->cache->evictFromCacheById($eachChild->getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
@ -151,13 +164,12 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
*/
|
*/
|
||||||
public function updateAcl(MutableAclInterface $acl)
|
public function updateAcl(MutableAclInterface $acl)
|
||||||
{
|
{
|
||||||
if (!$acl instanceof Acl) {
|
if (!$acl instanceof MutableAcl) {
|
||||||
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\PropelBundle\Security\Acl\Domain\Acl only.');
|
throw new \InvalidArgumentException('The given ACL is not tracked by this provider. Please provide \Propel\PropelBundle\Security\Acl\Domain\MutableAcl only.');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$modelEntries = EntryQuery::create()->findByAclIdentity($acl->getObjectIdentity(), array(), $this->connection);
|
$modelEntries = EntryQuery::create()->findByAclIdentity($acl->getObjectIdentity(), array(), $this->connection);
|
||||||
|
|
||||||
$objectIdentity = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($acl->getObjectIdentity(), $this->connection);
|
$objectIdentity = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($acl->getObjectIdentity(), $this->connection);
|
||||||
|
|
||||||
$this->connection->beginTransaction();
|
$this->connection->beginTransaction();
|
||||||
|
@ -194,6 +206,12 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
|
||||||
|
|
||||||
$this->connection->commit();
|
$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;
|
return true;
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
||||||
class AclTestCase extends TestCase
|
class AclTestCase extends TestCase
|
||||||
{
|
{
|
||||||
protected $con = null;
|
protected $con = null;
|
||||||
|
protected $cache = null;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
|
@ -87,7 +88,7 @@ class AclTestCase extends TestCase
|
||||||
|
|
||||||
protected function getAclProvider()
|
protected function getAclProvider()
|
||||||
{
|
{
|
||||||
return new MutableAclProvider(new PermissionGrantingStrategy(), $this->con);
|
return new MutableAclProvider(new PermissionGrantingStrategy(), $this->con, $this->cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getAclObjectIdentity($identifier = 1)
|
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;
|
namespace Propel\PropelBundle\Tests\Security\Acl;
|
||||||
|
|
||||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||||
|
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
||||||
|
use Propel\PropelBundle\Model\Acl\EntryPeer;
|
||||||
|
|
||||||
use Propel\PropelBundle\Security\Acl\AclProvider;
|
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 Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
||||||
|
|
||||||
use Propel\PropelBundle\Tests\AclTestCase;
|
use Propel\PropelBundle\Tests\AclTestCase;
|
||||||
|
use Propel\PropelBundle\Tests\Fixtures\Acl\ArrayCache as AclCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
|
@ -218,8 +221,39 @@ class AclProviderTest extends AclTestCase
|
||||||
return array($parentObj, $obj, $childObj);
|
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()
|
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\Model\Acl\ObjectIdentityQuery;
|
||||||
|
|
||||||
use Propel\PropelBundle\Tests\AclTestCase;
|
use Propel\PropelBundle\Tests\AclTestCase;
|
||||||
|
use Propel\PropelBundle\Tests\Fixtures\Acl\ArrayCache as AclCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||||
|
@ -241,4 +242,78 @@ class MutableAclProviderTest extends AclTestCase
|
||||||
$this->getAclProvider()->deleteAcl($this->getAclObjectIdentity(1));
|
$this->getAclProvider()->deleteAcl($this->getAclObjectIdentity(1));
|
||||||
$this->assertEquals(0, EntryQuery::create()->count($this->con));
|
$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