Added ACL related features
This commit is contained in:
parent
186de0e93c
commit
12bcfbde5e
|
@ -12,6 +12,7 @@ namespace Propel\PropelBundle\Command;
|
|||
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
@ -125,7 +126,7 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
|||
if ($this->input->hasOption('connection')) {
|
||||
$connections = $this->input->getOption('connection') ?: array($this->getContainer()->getParameter('propel.dbal.default_connection'));
|
||||
|
||||
if (!in_array($database['name'], $connections)) {
|
||||
if (!in_array((string) $database['name'], $connections)) {
|
||||
// we skip this schema because the connection name doesn't
|
||||
// match the input values
|
||||
unset($this->tempSchemas[$tempSchema]);
|
||||
|
@ -164,6 +165,27 @@ abstract class AbstractCommand extends ContainerAwareCommand
|
|||
return $this->getSchemaLocator()->locateFromBundles($kernel->getBundles());
|
||||
}
|
||||
|
||||
protected function runCommand(Command $command, array $parameters, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// add the command's name to the parameters
|
||||
array_unshift($parameters, $this->getName());
|
||||
|
||||
// merge the default parameters
|
||||
$parameters = array_merge(array(
|
||||
'--input-dir' => $this->cacheDir,
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
), $parameters);
|
||||
|
||||
if ($input->hasOption('platform')) {
|
||||
$parameters['--platform'] = $input->getOption('platform');
|
||||
}
|
||||
|
||||
$command->setApplication($this->getApplication());
|
||||
|
||||
// and run the sub-command
|
||||
return $command->run(new ArrayInput($parameters), $output);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an XML file which represents propel.configuration
|
||||
*
|
||||
|
|
124
Command/AclInitCommand.php
Normal file
124
Command/AclInitCommand.php
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?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\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class AclInitCommand extends AbstractCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Initialize "Access Control Lists" model and SQL')
|
||||
->addOption('force', null, InputOption::VALUE_NONE, 'Set this parameter to execute this action.')
|
||||
->addOption('connection', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Connection to use. Example: default, bookstore')
|
||||
->setHelp(<<<EOT
|
||||
The <info>%command.name%</info> command connects to the database and executes all SQL statements required to setup the ACL database, it also generates the ACL model.
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
The <info>--force</info> parameter has to be used to actually insert SQL.
|
||||
The <info>--connection</info> parameter allows you to change the connection to use.
|
||||
The default connection is the active connection (propel.dbal.default_connection).
|
||||
EOT
|
||||
)
|
||||
->setName('propel:acl:init')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$outputDir = realpath($this->getApplication()->getKernel()->getRootDir().'/../');
|
||||
|
||||
// Generate ACL model
|
||||
$modelBuildCmd = new \Propel\Generator\Command\ModelBuildCommand();
|
||||
$modelBuildArgs = array(
|
||||
'--output-dir' => $outputDir,
|
||||
);
|
||||
|
||||
if ($this->runCommand($modelBuildCmd, $modelBuildArgs, $input, $output) === 0) {
|
||||
$output->writeln(sprintf(
|
||||
'>> <info>%20s</info> Generated model classes from <comment>%s</comment>',
|
||||
$this->getApplication()->getKernel()->getBundle('PropelBundle')->getName(),
|
||||
'acl_schema.xml'
|
||||
));
|
||||
} else {
|
||||
$this->writeTaskError($output, 'model:build');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare SQL
|
||||
$sqlBuildCmd = new \Propel\Generator\Command\SqlBuildCommand();
|
||||
$sqlBuildArgs = array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
'--output-dir' => $this->getCacheDir(),
|
||||
);
|
||||
|
||||
if ($this->runCommand($sqlBuildCmd, $sqlBuildArgs, $input, $output) === 0) {
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'<comment>1</comment> <info>SQL file has been generated.</info>'
|
||||
);
|
||||
} else {
|
||||
$this->writeTaskError($output, 'sql:build');
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
// insert sql
|
||||
$sqlInsertCmd = new \Propel\Generator\Command\SqlInsertCommand();
|
||||
$sqlInsertArgs = array(
|
||||
'--connection' => $this->getConnections($input->getOption('connection')),
|
||||
);
|
||||
|
||||
if ($this->runCommand($sqlBuildCmd, $sqlBuildArgs, $input, $output) === 0) {
|
||||
$this->writeSection(
|
||||
$output,
|
||||
'<comment>1</comment> <info>SQL file has been inserted.</info>'
|
||||
);
|
||||
} else {
|
||||
$this->writeTaskError($output, 'sql:insert');
|
||||
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFinalSchemas(KernelInterface $kernel, BundleInterface $bundle = null)
|
||||
{
|
||||
$aclSchema = new \SplFileInfo($kernel->locateResource('@PropelBundle/Resources/acl_schema.xml'));
|
||||
|
||||
return array(
|
||||
array($kernel->getBundle('PropelBundle'), $aclSchema)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function initialize(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
parent::initialize($input, $output);
|
||||
|
||||
$this->cacheDir = $this->cacheDir . '/acl';
|
||||
|
||||
$this->setupBuildTimeFiles();
|
||||
}
|
||||
}
|
|
@ -12,8 +12,6 @@ namespace Propel\PropelBundle\Command;
|
|||
|
||||
use Propel\Generator\Command\AbstractCommand as BaseCommand;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
@ -60,25 +58,4 @@ abstract class WrappedCommand extends AbstractCommand
|
|||
|
||||
return $this->runCommand($command, $params, $input, $output);
|
||||
}
|
||||
|
||||
protected function runCommand(Command $command, array $parameters, InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
// add the command's name to the parameters
|
||||
array_unshift($parameters, $this->getName());
|
||||
|
||||
// merge the default parameters
|
||||
$parameters = array_merge(array(
|
||||
'--input-dir' => $this->cacheDir,
|
||||
'--verbose' => $input->getOption('verbose'),
|
||||
), $parameters);
|
||||
|
||||
if ($input->hasOption('platform')) {
|
||||
$parameters['--platform'] = $input->getOption('platform');
|
||||
}
|
||||
|
||||
$command->setApplication($this->getApplication());
|
||||
|
||||
// and run the sub-command
|
||||
return $command->run(new ArrayInput($parameters), $output);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,11 +36,7 @@ class PropelExtension extends Extension
|
|||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $processor->processConfiguration($configuration, $configs);
|
||||
|
||||
if (isset($config['logging']) && $config['logging']) {
|
||||
$logging = $config['logging'];
|
||||
} else {
|
||||
$logging = false;
|
||||
}
|
||||
$logging = isset($config['logging']) && $config['logging'];
|
||||
|
||||
$container->setParameter('propel.logging', $logging);
|
||||
|
||||
|
@ -49,6 +45,7 @@ class PropelExtension extends Extension
|
|||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('propel.xml');
|
||||
$loader->load('converters.xml');
|
||||
$loader->load('security.xml');
|
||||
}
|
||||
|
||||
// build properties
|
||||
|
|
43
Model/Acl/AclClass.php
Normal file
43
Model/Acl/AclClass.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\AclClass as BaseAclClass;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
|
||||
class AclClass extends BaseAclClass
|
||||
{
|
||||
/**
|
||||
* Return an AclClass for the given ACL ObjectIdentity.
|
||||
*
|
||||
* If none can be found, a new one will be saved.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\AclClass
|
||||
*/
|
||||
public static function fromAclObjectIdentity(ObjectIdentityInterface $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
$obj = AclClassQuery::create()
|
||||
->filterByType($objectIdentity->getType())
|
||||
->findOneOrCreate($con)
|
||||
;
|
||||
|
||||
if ($obj->isNew()) {
|
||||
$obj->save($con);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
18
Model/Acl/AclClassQuery.php
Normal file
18
Model/Acl/AclClassQuery.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\AclClassQuery as BaseAclClassQuery;
|
||||
|
||||
class AclClassQuery extends BaseAclClassQuery
|
||||
{
|
||||
|
||||
}
|
80
Model/Acl/Entry.php
Normal file
80
Model/Acl/Entry.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\Entry as BaseEntry;
|
||||
|
||||
use Propel\PropelBundle\Security\Acl\Domain\Entry as AclEntry;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\FieldEntry as AclFieldEntry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
|
||||
|
||||
class Entry extends BaseEntry
|
||||
{
|
||||
/**
|
||||
* Transform a given ACL entry into a Entry model.
|
||||
*
|
||||
* The entry will not be persisted!
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $aclEntry
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\Entry
|
||||
*/
|
||||
public static function fromAclEntry(EntryInterface $aclEntry)
|
||||
{
|
||||
$entry = new self();
|
||||
|
||||
// Already persisted before?
|
||||
if ($aclEntry->getId()) {
|
||||
$entry->setId($aclEntry->getId());
|
||||
}
|
||||
|
||||
$entry
|
||||
->setMask($aclEntry->getMask())
|
||||
->setGranting($aclEntry->isGranting())
|
||||
->setGrantingStrategy($aclEntry->getStrategy())
|
||||
->setSecurityIdentity(SecurityIdentity::fromAclIdentity($aclEntry->getSecurityIdentity()))
|
||||
;
|
||||
|
||||
if ($aclEntry instanceof FieldEntryInterface) {
|
||||
$entry->setFieldName($aclEntry->getField());
|
||||
}
|
||||
|
||||
if ($aclEntry instanceof AuditableEntryInterface) {
|
||||
$entry
|
||||
->setAuditFailure($aclEntry->isAuditFailure())
|
||||
->setAuditSuccess($aclEntry->isAuditSuccess())
|
||||
;
|
||||
}
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a given model entry into an ACL related Entry (ACE).
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry $modelEntry
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\EntryInterface
|
||||
*/
|
||||
public static function toAclEntry(Entry $modelEntry, AclInterface $acl)
|
||||
{
|
||||
if (null === $modelEntry->getFieldName()) {
|
||||
return new AclEntry($modelEntry, $acl);
|
||||
}
|
||||
|
||||
return new AclFieldEntry($modelEntry, $acl);
|
||||
}
|
||||
}
|
70
Model/Acl/EntryQuery.php
Normal file
70
Model/Acl/EntryQuery.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\EntryQuery as BaseEntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\Map\EntryTableMap;
|
||||
use Propel\PropelBundle\Model\Acl\Map\ObjectIdentityTableMap;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
|
||||
class EntryQuery extends BaseEntryQuery
|
||||
{
|
||||
/**
|
||||
* Return Entry objects filtered by an ACL related ObjectIdentity.
|
||||
*
|
||||
* @see find()
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity An ACL related ObjectIdentity.
|
||||
* @param array $securityIdentities A list of SecurityIdentity to filter by.
|
||||
* @param \ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findByAclIdentity(ObjectIdentityInterface $objectIdentity, array $securityIdentities = array(), ConnectionInterface $con = null)
|
||||
{
|
||||
$securityIds = array();
|
||||
foreach ($securityIdentities as $eachIdentity) {
|
||||
if (!$eachIdentity instanceof SecurityIdentityInterface) {
|
||||
if (is_object($eachIdentity)) {
|
||||
$errorMessage = sprintf('The list of security identities contains at least one invalid entry of class "%s". Please provide objects of classes implementing "Symfony\Component\Security\Acl\Model\SecurityIdentityInterface" only.', get_class($eachIdentity));
|
||||
} else {
|
||||
$errorMessage = sprintf('The list of security identities contains at least one invalid entry "%s". Please provide objects of classes implementing "Symfony\Component\Security\Acl\Model\SecurityIdentityInterface" only.', $eachIdentity);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException($errorMessage);
|
||||
}
|
||||
|
||||
if ($securityIdentity = SecurityIdentity::fromAclIdentity($eachIdentity)) {
|
||||
$securityIds[$securityIdentity->getId()] = $securityIdentity->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$this
|
||||
->useAclClassQuery(null, Criteria::INNER_JOIN)
|
||||
->filterByType((string) $objectIdentity->getType())
|
||||
->endUse()
|
||||
->leftJoinObjectIdentity()
|
||||
->add(ObjectIdentityTableMap::OBJECT_IDENTIFIER, (string) $objectIdentity->getIdentifier(), Criteria::EQUAL)
|
||||
->addOr(EntryTableMap::OBJECT_IDENTITY_ID, null, Criteria::ISNULL)
|
||||
;
|
||||
|
||||
if (!empty($securityIdentities)) {
|
||||
$this->filterBySecurityIdentityId($securityIds);
|
||||
}
|
||||
|
||||
return $this->find($con);
|
||||
}
|
||||
}
|
141
Model/Acl/ObjectIdentity.php
Normal file
141
Model/Acl/ObjectIdentity.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\ObjectIdentity as BaseObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\Map\ObjectIdentityTableMap;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
class ObjectIdentity extends BaseObjectIdentity
|
||||
{
|
||||
public function preInsert(ConnectionInterface $con = null)
|
||||
{
|
||||
// Compatibility with default implementation.
|
||||
$ancestor = new ObjectIdentityAncestor();
|
||||
$ancestor->setObjectIdentityRelatedByObjectIdentityId($this);
|
||||
$ancestor->setObjectIdentityRelatedByAncestorId($this);
|
||||
|
||||
$this->addObjectIdentityAncestorRelatedByAncestorId($ancestor);
|
||||
|
||||
if ($this->getParentObjectIdentityId()) {
|
||||
$this->updateAncestorsTree($con);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function preUpdate(ConnectionInterface $con = null)
|
||||
{
|
||||
if ($this->isColumnModified(ObjectIdentityTableMap::PARENT_OBJECT_IDENTITY_ID)) {
|
||||
$this->updateAncestorsTree($con);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function preDelete(ConnectionInterface $con = null)
|
||||
{
|
||||
// Only retrieve direct children, it's faster and grand children will be retrieved recursively.
|
||||
$children = ObjectIdentityQuery::create()->findChildren($this, $con);
|
||||
|
||||
$objIds = $children->getPrimaryKeys(false);
|
||||
$objIds[] = $this->getId();
|
||||
|
||||
$children->delete($con);
|
||||
|
||||
// Manually delete those for DBAdapter not capable of cascading the DELETE.
|
||||
ObjectIdentityAncestorQuery::create()
|
||||
->filterByObjectIdentityId($objIds, Criteria::IN)
|
||||
->delete($con)
|
||||
;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all ancestor entries to reflect changes on this instance.
|
||||
*
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentity $this
|
||||
*/
|
||||
protected function updateAncestorsTree(ConnectionInterface $con = null)
|
||||
{
|
||||
$con->beginTransaction();
|
||||
|
||||
$oldAncestors = ObjectIdentityQuery::create()->findAncestors($this, $con);
|
||||
|
||||
$children = ObjectIdentityQuery::create()->findGrandChildren($this, $con);
|
||||
$children->append($this);
|
||||
|
||||
if (count($oldAncestors)) {
|
||||
foreach ($children as $eachChild) {
|
||||
/*
|
||||
* Delete only those entries, that are ancestors based on the parent relation.
|
||||
* Ancestors of grand children up to the current node will be kept.
|
||||
*/
|
||||
$query = ObjectIdentityAncestorQuery::create()
|
||||
->filterByObjectIdentityId($eachChild->getId())
|
||||
->filterByObjectIdentityRelatedByAncestorId($oldAncestors, Criteria::IN)
|
||||
;
|
||||
|
||||
if ($eachChild->getId() !== $this->getId()) {
|
||||
$query->filterByAncestorId(array($eachChild->getId(), $this->getId()), Criteria::NOT_IN);
|
||||
} else {
|
||||
$query->filterByAncestorId($this->getId(), Criteria::NOT_EQUAL);
|
||||
}
|
||||
|
||||
$query->delete($con);
|
||||
}
|
||||
}
|
||||
|
||||
// This is the new parent object identity!
|
||||
$parent = $this->getObjectIdentityRelatedByParentObjectIdentityId($con);
|
||||
if (null !== $parent) {
|
||||
$newAncestors = ObjectIdentityQuery::create()->findAncestors($parent, $con);
|
||||
$newAncestors->append($parent);
|
||||
foreach ($newAncestors as $eachAncestor) {
|
||||
// This collection contains the current object identity!
|
||||
foreach ($children as $eachChild) {
|
||||
$ancestor = ObjectIdentityAncestorQuery::create()
|
||||
->filterByObjectIdentityId($eachChild->getId())
|
||||
->filterByAncestorId($eachAncestor->getId())
|
||||
->findOneOrCreate($con)
|
||||
;
|
||||
|
||||
// If the entry already exists, next please.
|
||||
if (!$ancestor->isNew()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($eachChild->getId() === $this->getId()) {
|
||||
// Do not save() here, as it would result in an infinite recursion loop!
|
||||
$this->addObjectIdentityAncestorRelatedByObjectIdentityId($ancestor);
|
||||
} else {
|
||||
// Save the new ancestor to avoid integrity constraint violation.
|
||||
$ancestor->save($con);
|
||||
|
||||
$eachChild
|
||||
->addObjectIdentityAncestorRelatedByObjectIdentityId($ancestor)
|
||||
->save($con)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
18
Model/Acl/ObjectIdentityAncestor.php
Normal file
18
Model/Acl/ObjectIdentityAncestor.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\ObjectIdentityAncestor as BaseObjectIdentityAncestor;
|
||||
|
||||
class ObjectIdentityAncestor extends BaseObjectIdentityAncestor
|
||||
{
|
||||
|
||||
}
|
18
Model/Acl/ObjectIdentityAncestorQuery.php
Normal file
18
Model/Acl/ObjectIdentityAncestorQuery.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\ObjectIdentityAncestorQuery as BaseObjectIdentityAncestorQuery;
|
||||
|
||||
class ObjectIdentityAncestorQuery extends BaseObjectIdentityAncestorQuery
|
||||
{
|
||||
|
||||
}
|
115
Model/Acl/ObjectIdentityQuery.php
Normal file
115
Model/Acl/ObjectIdentityQuery.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\Base\ObjectIdentityQuery as BaseObjectIdentityQuery;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
|
||||
class ObjectIdentityQuery extends BaseObjectIdentityQuery
|
||||
{
|
||||
/**
|
||||
* Filter by an ObjectIdentity object belonging to the given ACL related ObjectIdentity.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentityQuery $this
|
||||
*/
|
||||
public function filterByAclObjectIdentity(ObjectIdentityInterface $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
/*
|
||||
* Not using a JOIN here, because the filter may be applied on 'findOneOrCreate',
|
||||
* which is currently (Propel 1.6.4-dev) not working.
|
||||
*/
|
||||
$aclClass = AclClass::fromAclObjectIdentity($objectIdentity, $con);
|
||||
$this
|
||||
->filterByClassId($aclClass->getId())
|
||||
->filterByIdentifier($objectIdentity->getIdentifier())
|
||||
;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ObjectIdentity object belonging to the given ACL related ObjectIdentity.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\ObjectIdentity
|
||||
*/
|
||||
public function findOneByAclObjectIdentity(ObjectIdentityInterface $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->filterByAclObjectIdentity($objectIdentity, $con)
|
||||
->findOne($con)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all children of the given object identity.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findChildren(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->filterByObjectIdentityRelatedByParentObjectIdentityId($objectIdentity)
|
||||
->find($con)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all children and grand-children of the given object identity.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findGrandChildren(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->useObjectIdentityAncestorRelatedByObjectIdentityIdQuery()
|
||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity)
|
||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity, Criteria::NOT_EQUAL)
|
||||
->endUse()
|
||||
->find($con)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all ancestors of the given object identity.
|
||||
*
|
||||
* @param ObjectIdentity $objectIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \PropelObjectCollection
|
||||
*/
|
||||
public function findAncestors(ObjectIdentity $objectIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
return $this
|
||||
->useObjectIdentityAncestorRelatedByAncestorIdQuery()
|
||||
->filterByObjectIdentityRelatedByObjectIdentityId($objectIdentity)
|
||||
->filterByObjectIdentityRelatedByAncestorId($objectIdentity, Criteria::NOT_EQUAL)
|
||||
->endUse()
|
||||
->find($con)
|
||||
;
|
||||
}
|
||||
}
|
87
Model/Acl/SecurityIdentity.php
Normal file
87
Model/Acl/SecurityIdentity.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\SecurityIdentity as BaseSecurityIdentity;
|
||||
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
|
||||
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
|
||||
class SecurityIdentity extends BaseSecurityIdentity
|
||||
{
|
||||
/**
|
||||
* Transform a given mode security identity into an ACL related SecurityIdentity.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\SecurityIdentity $securityIdentity
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface
|
||||
*/
|
||||
public static function toAclIdentity(SecurityIdentity $securityIdentity)
|
||||
{
|
||||
$identifier = $securityIdentity->getIdentifier();
|
||||
|
||||
if ($securityIdentity->getUsername()) {
|
||||
if (false === strpos($identifier, '-')) {
|
||||
throw new \InvalidArgumentException('The given identifier does not resolve to a UserSecurityIdentity.');
|
||||
}
|
||||
|
||||
list($class, $username) = explode('-', $identifier, 2);
|
||||
|
||||
return new UserSecurityIdentity($username, $class);
|
||||
}
|
||||
|
||||
if (0 === strpos($identifier, 'ROLE_') or 0 === strpos($identifier, 'IS_AUTHENTICATED_')) {
|
||||
return new RoleSecurityIdentity($identifier);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('The security identity does not resolve to either UserSecurityIdentity or RoleSecurityIdentity.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a given ACL security identity into a SecurityIdentity model.
|
||||
*
|
||||
* If there is no model entry given, a new one will be created and saved to the database.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $aclIdentity
|
||||
* @param ConnectionInterface $con
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\SecurityIdentity
|
||||
*/
|
||||
public static function fromAclIdentity(SecurityIdentityInterface $aclIdentity, ConnectionInterface $con = null)
|
||||
{
|
||||
if ($aclIdentity instanceof UserSecurityIdentity) {
|
||||
$identifier = $aclIdentity->getClass().'-'.$aclIdentity->getUsername();
|
||||
$username = true;
|
||||
} elseif ($aclIdentity instanceof RoleSecurityIdentity) {
|
||||
$identifier = $aclIdentity->getRole();
|
||||
$username = false;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('The ACL identity must either be an instance of UserSecurityIdentity or RoleSecurityIdentity.');
|
||||
}
|
||||
|
||||
$obj = SecurityIdentityQuery::create()
|
||||
->filterByIdentifier($identifier)
|
||||
->filterByUsername($username)
|
||||
->findOneOrCreate($con)
|
||||
;
|
||||
|
||||
if ($obj->isNew()) {
|
||||
$obj->save($con);
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
}
|
18
Model/Acl/SecurityIdentityQuery.php
Normal file
18
Model/Acl/SecurityIdentityQuery.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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\Model\Acl;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Base\SecurityIdentityQuery as BaseSecurityIdentityQuery;
|
||||
|
||||
class SecurityIdentityQuery extends BaseSecurityIdentityQuery
|
||||
{
|
||||
|
||||
}
|
104
Resources/acl_schema.xml
Normal file
104
Resources/acl_schema.xml
Normal file
|
@ -0,0 +1,104 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<database name="default" namespace="Propel\PropelBundle\Model\Acl" defaultIdMethod="native" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://xsd.propelorm.org/1.6/database.xsd">
|
||||
<table name="acl_classes" phpName="AclClass">
|
||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||
<column name="class_type" type="varchar" size="200" required="true" phpName="Type" />
|
||||
|
||||
<unique>
|
||||
<unique-column name="class_type" />
|
||||
</unique>
|
||||
</table>
|
||||
|
||||
<table name="acl_security_identities" phpName="SecurityIdentity">
|
||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||
<column name="identifier" type="varchar" size="200" required="true" />
|
||||
<column name="username" type="boolean" required="true" />
|
||||
|
||||
<unique>
|
||||
<unique-column name="identifier" />
|
||||
<unique-column name="username" />
|
||||
</unique>
|
||||
</table>
|
||||
|
||||
<table name="acl_object_identities" phpName="ObjectIdentity">
|
||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||
<column name="class_id" type="integer" required="true" />
|
||||
<column name="object_identifier" type="varchar" size="200" required="true" phpName="Identifier" />
|
||||
<column name="parent_object_identity_id" type="integer" required="false" defaultValue="null" />
|
||||
<column name="entries_inheriting" type="boolean" required="true" defaultValue="true" />
|
||||
|
||||
<unique>
|
||||
<unique-column name="class_id" />
|
||||
<unique-column name="object_identifier" />
|
||||
</unique>
|
||||
|
||||
<index>
|
||||
<index-column name="parent_object_identity_id" />
|
||||
</index>
|
||||
|
||||
<foreign-key foreignTable="acl_classes" onDelete="RESTRICT" onUpdate="CASCADE">
|
||||
<reference local="class_id" foreign="id" />
|
||||
</foreign-key>
|
||||
<foreign-key foreignTable="acl_object_identities" onDelete="RESTRICT" onUpdate="CASCADE">
|
||||
<reference local="parent_object_identity_id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
||||
<table name="acl_object_identity_ancestors" phpName="ObjectIdentityAncestor" heavyIndexing="true">
|
||||
<column name="object_identity_id" type="integer" primaryKey="true" />
|
||||
<column name="ancestor_id" type="integer" primaryKey="true" />
|
||||
|
||||
<foreign-key foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="object_identity_id" foreign="id" />
|
||||
</foreign-key>
|
||||
<foreign-key foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="ancestor_id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
||||
<table name="acl_entries" phpName="Entry">
|
||||
<column name="id" type="integer" autoIncrement="true" primaryKey="true" />
|
||||
<column name="class_id" type="integer" required="true" />
|
||||
<column name="object_identity_id" type="integer" required="false" defaultValue="null" />
|
||||
<column name="security_identity_id" type="integer" required="true" />
|
||||
<column name="field_name" type="varchar" size="50" />
|
||||
<column name="ace_order" type="integer" required="true" />
|
||||
<column name="mask" type="integer" required="true" />
|
||||
<column name="granting" type="boolean" required="true" />
|
||||
<column name="granting_strategy" type="varchar" size="30" required="true" />
|
||||
<column name="audit_success" type="boolean" required="true" defaultValue="false" />
|
||||
<column name="audit_failure" type="boolean" required="true" defaultValue="true" />
|
||||
|
||||
<unique>
|
||||
<unique-column name="class_id" />
|
||||
<unique-column name="object_identity_id" />
|
||||
<unique-column name="field_name" />
|
||||
<unique-column name="ace_order" />
|
||||
</unique>
|
||||
|
||||
<index>
|
||||
<index-column name="class_id" />
|
||||
<index-column name="object_identity_id" />
|
||||
<index-column name="security_identity_id" />
|
||||
</index>
|
||||
<index>
|
||||
<index-column name="class_id" />
|
||||
</index>
|
||||
<index>
|
||||
<index-column name="object_identity_id" />
|
||||
</index>
|
||||
<index>
|
||||
<index-column name="security_identity_id" />
|
||||
</index>
|
||||
|
||||
<foreign-key foreignTable="acl_classes" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="class_id" foreign="id" />
|
||||
</foreign-key>
|
||||
<foreign-key foreignTable="acl_object_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="object_identity_id" foreign="id" />
|
||||
</foreign-key>
|
||||
<foreign-key foreignTable="acl_security_identities" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="security_identity_id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
</database>
|
21
Resources/config/security.xml
Normal file
21
Resources/config/security.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="propel.security.acl.provider.model.class">Propel\PropelBundle\Security\Acl\AuditableAclProvider</parameter>
|
||||
<parameter key="propel.security.user.provider.class">Propel\PropelBundle\Security\User\PropelUserProvider</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="propel.security.acl.provider" class="%propel.security.acl.provider.model.class%" public="false">
|
||||
<argument type="service" id="security.acl.permission_granting_strategy" />
|
||||
<argument type="service" id="propel.security.acl.connection" on-invalid="null" />
|
||||
<argument type="service" id="security.acl.cache" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
<service id="propel.security.user.provider" class="%propel.security.user.provider.class%" abstract="true" public="false" />
|
||||
</services>
|
||||
</container>
|
181
Security/Acl/AclProvider.php
Normal file
181
Security/Acl/AclProvider.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?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\Security\Acl;
|
||||
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
|
||||
use Propel\PropelBundle\Security\Acl\Domain\Acl;
|
||||
|
||||
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
|
||||
|
||||
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||
|
||||
/**
|
||||
* An implementation of the AclProviderInterface using Propel ORM.
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class AclProvider implements AclProviderInterface
|
||||
{
|
||||
protected $permissionGrantingStrategy;
|
||||
protected $connection;
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param ConnectionInterface $con
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||
*/
|
||||
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, ConnectionInterface $connection = null, AclCacheInterface $cache = null)
|
||||
{
|
||||
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
|
||||
$this->connection = $connection;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all child object identities from the database.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $parentObjectIdentity
|
||||
* @param bool $directChildrenOnly
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findChildren(ObjectIdentityInterface $parentObjectIdentity, $directChildrenOnly = false)
|
||||
{
|
||||
$modelIdentity = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($parentObjectIdentity, $this->connection);
|
||||
if (empty($modelIdentity)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($directChildrenOnly) {
|
||||
$collection = ObjectIdentityQuery::create()->findChildren($modelIdentity, $this->connection);
|
||||
} else {
|
||||
$collection = ObjectIdentityQuery::create()->findGrandChildren($modelIdentity, $this->connection);
|
||||
}
|
||||
|
||||
$children = array();
|
||||
foreach ($collection as $eachChild) {
|
||||
$children[] = new ObjectIdentity($eachChild->getIdentifier(), $eachChild->getAclClass($this->connection)->getType());
|
||||
}
|
||||
|
||||
return $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ACL that belongs to the given object identity
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\AclNotFoundException
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $securityIdentities
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\AclInterface
|
||||
*/
|
||||
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, $this->connection);
|
||||
|
||||
if (0 === count($collection)) {
|
||||
if (empty($securityIdentities)) {
|
||||
$errorMessage = 'There is no ACL available for this object identity. Please create one using the MutableAclProvider.';
|
||||
} else {
|
||||
$errorMessage = 'There is at least no ACL for this object identity and the given security identities. Try retrieving the ACL without security identity filter and add ACEs for the security identities.';
|
||||
}
|
||||
|
||||
throw new AclNotFoundException($errorMessage);
|
||||
}
|
||||
|
||||
$loadedSecurityIdentities = array();
|
||||
foreach ($collection as $eachEntry) {
|
||||
if (!isset($loadedSecurityIdentities[$eachEntry->getSecurityIdentity()->getId()])) {
|
||||
$loadedSecurityIdentities[$eachEntry->getSecurityIdentity()->getId()] = SecurityIdentity::toAclIdentity($eachEntry->getSecurityIdentity());
|
||||
}
|
||||
}
|
||||
|
||||
$parentAcl = null;
|
||||
$entriesInherited = true;
|
||||
|
||||
if (null !== $modelObj) {
|
||||
$entriesInherited = $modelObj->getEntriesInheriting();
|
||||
if (null !== $modelObj->getParentObjectIdentityId()) {
|
||||
$parentObj = $modelObj->getObjectIdentityRelatedByParentObjectIdentityId($this->connection);
|
||||
try {
|
||||
$parentAcl = $this->findAcl(new ObjectIdentity($parentObj->getIdentifier(), $parentObj->getAclClass($this->connection)->getType()));
|
||||
} catch (AclNotFoundException $e) {
|
||||
/*
|
||||
* This happens e.g. if the parent ACL is created, but does not contain any ACE by now.
|
||||
* The ACEs may be applied later on.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getAcl($collection, $objectIdentity, $loadedSecurityIdentities, $parentAcl, $entriesInherited);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ACLs that belong to the given object identities
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\AclNotFoundException When at least one object identity is missing its ACL.
|
||||
*
|
||||
* @param array $objectIdentities an array of ObjectIdentityInterface implementations
|
||||
* @param array $securityIdentities an array of SecurityIdentityInterface implementations
|
||||
*
|
||||
* @return \SplObjectStorage mapping the passed object identities to ACLs
|
||||
*/
|
||||
public function findAcls(array $objectIdentities, array $securityIdentities = array())
|
||||
{
|
||||
$result = new \SplObjectStorage();
|
||||
foreach ($objectIdentities as $eachIdentity) {
|
||||
$result[$eachIdentity] = $this->findAcl($eachIdentity, $securityIdentities);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ACL.
|
||||
*
|
||||
* @param ObjectCollection $collection
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Acl
|
||||
*/
|
||||
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||
{
|
||||
return new Acl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited);
|
||||
}
|
||||
}
|
39
Security/Acl/AuditableAclProvider.php
Normal file
39
Security/Acl/AuditableAclProvider.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?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\Security\Acl;
|
||||
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\AuditableAcl;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class AuditableAclProvider extends MutableAclProvider
|
||||
{
|
||||
/**
|
||||
* Get an ACL for this provider.
|
||||
*
|
||||
* @param Propel\Runtime\Collection\ObjectCollection $collection
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\AuditableAcl
|
||||
*/
|
||||
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||
{
|
||||
return new AuditableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
||||
}
|
||||
}
|
316
Security/Acl/Domain/Acl.php
Normal file
316
Security/Acl/Domain/Acl.php
Normal file
|
@ -0,0 +1,316 @@
|
|||
<?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\Security\Acl\Domain;
|
||||
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
|
||||
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
|
||||
/**
|
||||
* An ACL implementation that is immutable based on data from a ObjectCollection of Propel\PropelBundle\Model\Acl\Entry.
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class Acl implements AclInterface
|
||||
{
|
||||
protected $model = 'Propel\PropelBundle\Model\Acl\Entry';
|
||||
|
||||
protected $classAces = array();
|
||||
protected $classFieldAces = array();
|
||||
protected $objectAces = array();
|
||||
protected $objectFieldAces = array();
|
||||
|
||||
protected $objectIdentity;
|
||||
protected $parentAcl;
|
||||
protected $permissionGrantingStrategy;
|
||||
protected $inherited;
|
||||
|
||||
protected $loadedSecurityIdentities = array();
|
||||
|
||||
/**
|
||||
* A list of known associated fields on this ACL.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fields = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ObjectCollection $entries
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
*/
|
||||
public function __construct(ObjectCollection $entries, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||
{
|
||||
if ($entries->getModel() !== $this->model) {
|
||||
throw new AclException(sprintf('The given collection does not contain models of class "%s" but of class "%s".', $this->model, $entries->getModel()));
|
||||
}
|
||||
|
||||
foreach ($entries as $eachEntry) {
|
||||
if (null === $eachEntry->getFieldName() and null === $eachEntry->getObjectIdentityId()) {
|
||||
$this->classAces[] = new Entry($eachEntry, $this);
|
||||
}
|
||||
|
||||
if (null !== $eachEntry->getFieldName() and null === $eachEntry->getObjectIdentityId()) {
|
||||
if (empty($this->classFieldAces[$eachEntry->getFieldName()])) {
|
||||
$this->classFieldAces[$eachEntry->getFieldName()] = array();
|
||||
$this->updateFields($eachEntry->getFieldName());
|
||||
}
|
||||
|
||||
$this->classFieldAces[$eachEntry->getFieldName()][] = new FieldEntry($eachEntry, $this);
|
||||
}
|
||||
|
||||
if (null === $eachEntry->getFieldName() and null !== $eachEntry->getObjectIdentityId()) {
|
||||
$this->objectAces[] = new Entry($eachEntry, $this);
|
||||
}
|
||||
|
||||
if (null !== $eachEntry->getFieldName() and null !== $eachEntry->getObjectIdentityId()) {
|
||||
if (empty($this->objectFieldAces[$eachEntry->getFieldName()])) {
|
||||
$this->objectFieldAces[$eachEntry->getFieldName()] = array();
|
||||
$this->updateFields($eachEntry->getFieldName());
|
||||
}
|
||||
|
||||
$this->objectFieldAces[$eachEntry->getFieldName()][] = new FieldEntry($eachEntry, $this);
|
||||
}
|
||||
}
|
||||
|
||||
$this->objectIdentity = $objectIdentity;
|
||||
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
|
||||
$this->parentAcl = $parentAcl;
|
||||
$this->inherited = $inherited;
|
||||
$this->loadedSecurityIdentities = $loadedSecurityIdentities;
|
||||
|
||||
$this->fields = array_unique($this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all class-based ACEs associated with this ACL
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClassAces()
|
||||
{
|
||||
return $this->classAces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all class-field-based ACEs associated with this ACL
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getClassFieldAces($field)
|
||||
{
|
||||
return isset($this->classFieldAces[$field]) ? $this->classFieldAces[$field] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all object-based ACEs associated with this ACL
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getObjectAces()
|
||||
{
|
||||
return $this->objectAces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all object-field-based ACEs associated with this ACL
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getObjectFieldAces($field)
|
||||
{
|
||||
return isset($this->objectFieldAces[$field]) ? $this->objectFieldAces[$field] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object identity associated with this ACL
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface
|
||||
*/
|
||||
public function getObjectIdentity()
|
||||
{
|
||||
return $this->objectIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent ACL, or null if there is none.
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\AclInterface|null
|
||||
*/
|
||||
public function getParentAcl()
|
||||
{
|
||||
return $this->parentAcl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this ACL is inheriting ACEs from a parent ACL.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEntriesInheriting()
|
||||
{
|
||||
return $this->inherited;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether field access is granted
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $masks
|
||||
* @param array $securityIdentities
|
||||
* @param bool $administrativeMode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFieldGranted($field, array $masks, array $securityIdentities, $administrativeMode = false)
|
||||
{
|
||||
return $this->permissionGrantingStrategy->isFieldGranted($this, $field, $masks, $securityIdentities, $administrativeMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether access is granted
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\NoAceFoundException when no ACE was applicable for this request
|
||||
*
|
||||
* @param array $masks
|
||||
* @param array $securityIdentities
|
||||
* @param bool $administrativeMode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isGranted(array $masks, array $securityIdentities, $administrativeMode = false)
|
||||
{
|
||||
return $this->permissionGrantingStrategy->isGranted($this, $masks, $securityIdentities, $administrativeMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the ACL has loaded ACEs for all of the passed security identities
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @param mixed $securityIdentities an implementation of SecurityIdentityInterface, or an array thereof
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSidLoaded($securityIdentities)
|
||||
{
|
||||
if (!is_array($securityIdentities)) {
|
||||
$securityIdentities = array($securityIdentities);
|
||||
}
|
||||
|
||||
$found = 0;
|
||||
foreach ($securityIdentities as $eachSecurityIdentity) {
|
||||
if (!$eachSecurityIdentity instanceof SecurityIdentityInterface) {
|
||||
throw new \InvalidArgumentException('At least one entry of the given list is not implementing the "SecurityIdentityInterface".');
|
||||
}
|
||||
|
||||
foreach ($this->loadedSecurityIdentities as $eachLoadedIdentity) {
|
||||
if ($eachSecurityIdentity->equals($eachLoadedIdentity)) {
|
||||
$found++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ($found === count($securityIdentities));
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.serialize.php
|
||||
*
|
||||
* @return string the string representation of the object or &null;
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array(
|
||||
$this->model,
|
||||
$this->classAces,
|
||||
$this->classFieldAces,
|
||||
$this->objectAces,
|
||||
$this->objectFieldAces,
|
||||
$this->objectIdentity,
|
||||
$this->parentAcl,
|
||||
$this->permissionGrantingStrategy,
|
||||
$this->inherited,
|
||||
$this->loadedSecurityIdentities,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized
|
||||
*
|
||||
* @return mixed the original value unserialized.
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list(
|
||||
$this->model,
|
||||
$this->classAces,
|
||||
$this->classFieldAces,
|
||||
$this->objectAces,
|
||||
$this->objectFieldAces,
|
||||
$this->objectIdentity,
|
||||
$this->parentAcl,
|
||||
$this->permissionGrantingStrategy,
|
||||
$this->inherited,
|
||||
$this->loadedSecurityIdentities,
|
||||
) = unserialize($serialized);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of associated fields on this ACL.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFields()
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the internal list of associated fields on this ACL.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Acl $this
|
||||
*/
|
||||
protected function updateFields($field)
|
||||
{
|
||||
if (!in_array($field, $this->fields)) {
|
||||
$this->fields[] = $field;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
103
Security/Acl/Domain/AuditableAcl.php
Normal file
103
Security/Acl/Domain/AuditableAcl.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?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\Security\Acl\Domain;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AuditableAclInterface;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class AuditableAcl extends MutableAcl implements AuditableAclInterface
|
||||
{
|
||||
/**
|
||||
* Updates auditing for class-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateClassAuditing($index, $auditSuccess, $auditFailure)
|
||||
{
|
||||
$this->updateAuditing($this->classAces, $index, $auditSuccess, $auditFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates auditing for class-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateClassFieldAuditing($index, $field, $auditSuccess, $auditFailure)
|
||||
{
|
||||
$this->validateField($this->classFieldAces, $field);
|
||||
$this->updateAuditing($this->classFieldAces[$field], $index, $auditSuccess, $auditFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates auditing for object-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateObjectAuditing($index, $auditSuccess, $auditFailure)
|
||||
{
|
||||
$this->updateAuditing($this->objectAces, $index, $auditSuccess, $auditFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates auditing for object-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*/
|
||||
public function updateObjectFieldAuditing($index, $field, $auditSuccess, $auditFailure)
|
||||
{
|
||||
$this->validateField($this->objectFieldAces, $field);
|
||||
$this->updateAuditing($this->objectFieldAces[$field], $index, $auditSuccess, $auditFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update auditing on a single ACE.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param bool $auditSuccess
|
||||
* @param bool $auditFailure
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\AuditableAcl $this
|
||||
*/
|
||||
protected function updateAuditing(array &$list, $index, $auditSuccess, $auditFailure)
|
||||
{
|
||||
if (!is_bool($auditSuccess) or !is_bool($auditFailure)) {
|
||||
throw new \InvalidArgumentException('The given auditing flags are invalid. Please provide boolean only.');
|
||||
}
|
||||
|
||||
$this->validateIndex($list, $index);
|
||||
|
||||
$entry = ModelEntry::fromAclEntry($list[$index])
|
||||
->setAuditSuccess($auditSuccess)
|
||||
->setAuditFailure($auditFailure)
|
||||
;
|
||||
|
||||
$list[$index] = ModelEntry::toAclEntry($entry, $this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
192
Security/Acl/Domain/Entry.php
Normal file
192
Security/Acl/Domain/Entry.php
Normal file
|
@ -0,0 +1,192 @@
|
|||
<?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\Security\Acl\Domain;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
|
||||
/**
|
||||
* An ACE implementation retrieving data from a given Propel\PropelBundle\Model\Acl\Entry.
|
||||
*
|
||||
* The entry is only used to grab a "snapshot" of its data as an EntryInterface is immutable!
|
||||
*
|
||||
* @see \Symfony\Component\Security\Acl\Model\EntryInterface
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class Entry implements AuditableEntryInterface
|
||||
{
|
||||
protected $acl;
|
||||
|
||||
protected $id;
|
||||
protected $securityIdentity;
|
||||
protected $mask;
|
||||
protected $isGranting;
|
||||
protected $strategy;
|
||||
protected $auditSuccess;
|
||||
protected $auditFailure;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry $entry
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||
*/
|
||||
public function __construct(ModelEntry $entry, AclInterface $acl)
|
||||
{
|
||||
$this->acl = $acl;
|
||||
$this->securityIdentity = SecurityIdentity::toAclIdentity($entry->getSecurityIdentity());
|
||||
|
||||
/*
|
||||
* A new ACE (from a MutableAcl) does not have an ID,
|
||||
* but will be persisted by the MutableAclProvider afterwards, if issued.
|
||||
*/
|
||||
if ($entry->getId()) {
|
||||
$this->id = $entry->getId();
|
||||
}
|
||||
|
||||
$this->mask = $entry->getMask();
|
||||
$this->isGranting = $entry->getGranting();
|
||||
$this->strategy = $entry->getGrantingStrategy();
|
||||
$this->auditFailure = $entry->getAuditFailure();
|
||||
$this->auditSuccess = $entry->getAuditSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.serialize.php
|
||||
*
|
||||
* @return string the string representation of the object or &null;
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array(
|
||||
$this->acl,
|
||||
$this->securityIdentity,
|
||||
$this->id,
|
||||
$this->mask,
|
||||
$this->isGranting,
|
||||
$this->strategy,
|
||||
$this->auditFailure,
|
||||
$this->auditSuccess,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized
|
||||
*
|
||||
* @return mixed the original value unserialized.
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list(
|
||||
$this->acl,
|
||||
$this->securityIdentity,
|
||||
$this->id,
|
||||
$this->mask,
|
||||
$this->isGranting,
|
||||
$this->strategy,
|
||||
$this->auditFailure,
|
||||
$this->auditSuccess,
|
||||
) = unserialize($serialized);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ACL this ACE is associated with.
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\AclInterface
|
||||
*/
|
||||
public function getAcl()
|
||||
{
|
||||
return $this->acl;
|
||||
}
|
||||
|
||||
/**
|
||||
* The security identity associated with this ACE
|
||||
*
|
||||
* @return \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface
|
||||
*/
|
||||
public function getSecurityIdentity()
|
||||
{
|
||||
return $this->securityIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* The primary key of this ACE
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The permission mask of this ACE
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getMask()
|
||||
{
|
||||
return $this->mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* The strategy for comparing masks
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStrategy()
|
||||
{
|
||||
return $this->strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this ACE is granting, or denying
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isGranting()
|
||||
{
|
||||
return $this->isGranting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether auditing for successful grants is turned on
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuditFailure()
|
||||
{
|
||||
return $this->auditFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether auditing for successful denies is turned on
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuditSuccess()
|
||||
{
|
||||
return $this->auditSuccess;
|
||||
}
|
||||
}
|
101
Security/Acl/Domain/FieldEntry.php
Normal file
101
Security/Acl/Domain/FieldEntry.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?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\Security\Acl\Domain;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
|
||||
|
||||
/**
|
||||
* An ACE implementation retrieving data from a given \Propel\PropelBundle\Model\Acl\Entry.
|
||||
*
|
||||
* The entry is only used to grab a "snapshot" of its data as an \Symfony\Component\Security\Acl\Model\EntryInterface is immutable!
|
||||
*
|
||||
* @see \Symfony\Component\Security\Acl\Model\EntryInterface
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class FieldEntry extends Entry implements FieldEntryInterface
|
||||
{
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry $entry
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $acl
|
||||
*/
|
||||
public function __construct(ModelEntry $entry, AclInterface $acl)
|
||||
{
|
||||
$this->field = $entry->getFieldName();
|
||||
|
||||
parent::__construct($entry, $acl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field used for this entry.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getField()
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.serialize.php
|
||||
*
|
||||
* @return string the string representation of the object or &null;
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array(
|
||||
$this->acl,
|
||||
$this->securityIdentity,
|
||||
$this->id,
|
||||
$this->mask,
|
||||
$this->isGranting,
|
||||
$this->strategy,
|
||||
$this->auditFailure,
|
||||
$this->auditSuccess,
|
||||
$this->field,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized
|
||||
*
|
||||
* @return mixed the original value unserialized.
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list(
|
||||
$this->acl,
|
||||
$this->securityIdentity,
|
||||
$this->id,
|
||||
$this->mask,
|
||||
$this->isGranting,
|
||||
$this->strategy,
|
||||
$this->auditFailure,
|
||||
$this->auditSuccess,
|
||||
$this->field,
|
||||
) = unserialize($serialized);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
531
Security/Acl/Domain/MutableAcl.php
Normal file
531
Security/Acl/Domain/MutableAcl.php
Normal file
|
@ -0,0 +1,531 @@
|
|||
<?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\Security\Acl\Domain;
|
||||
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
|
||||
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\MutableAclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
|
||||
|
||||
/**
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class MutableAcl extends Acl implements MutableAclInterface
|
||||
{
|
||||
/**
|
||||
* The id of the current ACL.
|
||||
*
|
||||
* It's the id of the ObjectIdentity model.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* A reference to the ObjectIdentity this ACL is mapped to.
|
||||
*
|
||||
* @var \Propel\PropelBundle\Model\Acl\ObjectIdentity
|
||||
*/
|
||||
protected $modelObjectIdentity;
|
||||
|
||||
/**
|
||||
* A connection to be used for all changes on the ACL.
|
||||
*
|
||||
* @var ConnectionInterface
|
||||
*/
|
||||
protected $con;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ObjectCollection $entries
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
* @param ConnectionInterface $con
|
||||
*/
|
||||
public function __construct(ObjectCollection $entries, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true, ConnectionInterface $con = null)
|
||||
{
|
||||
parent::__construct($entries, $objectIdentity, $permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited);
|
||||
|
||||
$this->modelObjectIdentity = ObjectIdentityQuery::create()
|
||||
->filterByAclObjectIdentity($objectIdentity, $con)
|
||||
->findOneOrCreate($con)
|
||||
;
|
||||
|
||||
if ($this->modelObjectIdentity->isNew()) {
|
||||
$this->modelObjectIdentity->save($con);
|
||||
}
|
||||
|
||||
$this->id = $this->modelObjectIdentity->getId();
|
||||
|
||||
$this->con = $con;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary key of this ACL
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether entries are inherited
|
||||
*
|
||||
* @param bool $boolean
|
||||
*/
|
||||
public function setEntriesInheriting($boolean)
|
||||
{
|
||||
$this->inherited = $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent ACL
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface|null $acl
|
||||
*/
|
||||
public function setParentAcl(AclInterface $acl = null)
|
||||
{
|
||||
$this->parentAcl = $acl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a class-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
*/
|
||||
public function deleteClassAce($index)
|
||||
{
|
||||
$this->deleteIndex($this->classAces, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a class-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
*/
|
||||
public function deleteClassFieldAce($index, $field)
|
||||
{
|
||||
$this
|
||||
->validateField($this->classFieldAces, $field)
|
||||
->deleteIndex($this->classFieldAces[$field], $index)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an object-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
*/
|
||||
public function deleteObjectAce($index)
|
||||
{
|
||||
$this->deleteIndex($this->objectAces, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an object-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
*/
|
||||
public function deleteObjectFieldAce($index, $field)
|
||||
{
|
||||
$this
|
||||
->validateField($this->objectFieldAces, $field)
|
||||
->deleteIndex($this->objectFieldAces[$field], $index)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a class-based ACE
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param bool $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertClassAce(SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
$this->insertToList($this->classAces, $index, $this->createAce($mask, $index, $securityIdentity, $strategy, $granting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a class-field-based ACE
|
||||
*
|
||||
* @param string $field
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertClassFieldAce($field, SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
if (!isset($this->classFieldAces[$field])) {
|
||||
$this->classFieldAces[$field] = array();
|
||||
}
|
||||
|
||||
$this->insertToList($this->classFieldAces[$field], $index, $this->createAce($mask, $index, $securityIdentity, $strategy, $granting, $field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an object-based ACE
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertObjectAce(SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
$this->insertToList($this->objectAces, $index, $this->createAce($mask, $index, $securityIdentity, $strategy, $granting));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an object-field-based ACE
|
||||
*
|
||||
* @param string $field
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param integer $mask
|
||||
* @param integer $index
|
||||
* @param boolean $granting
|
||||
* @param string $strategy
|
||||
*/
|
||||
public function insertObjectFieldAce($field, SecurityIdentityInterface $securityIdentity, $mask, $index = 0, $granting = true, $strategy = null)
|
||||
{
|
||||
if (!isset($this->objectFieldAces[$field])) {
|
||||
$this->objectFieldAces[$field] = array();
|
||||
}
|
||||
|
||||
$this->insertToList($this->objectFieldAces[$field], $index, $this->createAce($mask, $index, $securityIdentity, $strategy, $granting, $field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a class-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateClassAce($index, $mask, $strategy = null)
|
||||
{
|
||||
$this->updateAce($this->classAces, $index, $mask, $strategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a class-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateClassFieldAce($index, $field, $mask, $strategy = null)
|
||||
{
|
||||
$this
|
||||
->validateField($this->classFieldAces, $field)
|
||||
->updateAce($this->classFieldAces[$field], $index, $mask, $strategy)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an object-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateObjectAce($index, $mask, $strategy = null)
|
||||
{
|
||||
$this->updateAce($this->objectAces, $index, $mask, $strategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an object-field-based ACE
|
||||
*
|
||||
* @param integer $index
|
||||
* @param string $field
|
||||
* @param integer $mask
|
||||
* @param string $strategy if null the strategy should not be changed
|
||||
*/
|
||||
public function updateObjectFieldAce($index, $field, $mask, $strategy = null)
|
||||
{
|
||||
$this->validateField($this->objectFieldAces, $field);
|
||||
$this->updateAce($this->objectFieldAces[$field], $index, $mask, $strategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation of object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.serialize.php
|
||||
*
|
||||
* @return string the string representation of the object or &null;
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array(
|
||||
$this->id,
|
||||
$this->modelObjectIdentity,
|
||||
$this->model,
|
||||
$this->classAces,
|
||||
$this->classFieldAces,
|
||||
$this->objectAces,
|
||||
$this->objectFieldAces,
|
||||
$this->objectIdentity,
|
||||
$this->parentAcl,
|
||||
$this->permissionGrantingStrategy,
|
||||
$this->inherited,
|
||||
$this->loadedSecurityIdentities,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object
|
||||
*
|
||||
* @link http://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized
|
||||
*
|
||||
* @return mixed the original value unserialized.
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
list(
|
||||
$this->id,
|
||||
$this->modelObjectIdentity,
|
||||
$this->model,
|
||||
$this->classAces,
|
||||
$this->classFieldAces,
|
||||
$this->objectAces,
|
||||
$this->objectFieldAces,
|
||||
$this->objectIdentity,
|
||||
$this->parentAcl,
|
||||
$this->permissionGrantingStrategy,
|
||||
$this->inherited,
|
||||
$this->loadedSecurityIdentities,
|
||||
) = unserialize($serialized);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a given entry into the list on the given index by shifting all others.
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param \Propel\PropelBundle\Model\Acl\Entry\Entry $entry
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function insertToList(array &$list, $index, Entry $entry)
|
||||
{
|
||||
$this->isWithinBounds($list, $index);
|
||||
|
||||
if ($entry instanceof FieldEntry) {
|
||||
$this->updateFields($entry->getField());
|
||||
}
|
||||
|
||||
$list = array_merge(
|
||||
array_slice($list, 0, $index),
|
||||
array($entry),
|
||||
array_splice($list, $index)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single ACE of this ACL.
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
* @param int $mask
|
||||
* @param string $strategy
|
||||
* @param string $field
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function updateAce(array &$list, $index, $mask, $strategy = null)
|
||||
{
|
||||
$this->validateIndex($list, $index);
|
||||
|
||||
$entry = ModelEntry::fromAclEntry($list[$index]);
|
||||
|
||||
// Apply updates
|
||||
$entry->setMask($mask);
|
||||
if (null !== $strategy) {
|
||||
$entry->setGrantingStrategy($strategy);
|
||||
}
|
||||
|
||||
$list[$index] = ModelEntry::toAclEntry($entry, $this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ACE of the given list and index.
|
||||
*
|
||||
* The list will be re-ordered to have a valid 0..x list.
|
||||
*
|
||||
* @param array $list
|
||||
* @param $index
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function deleteIndex(array &$list, $index)
|
||||
{
|
||||
$this->validateIndex($list, $index);
|
||||
unset($list[$index]);
|
||||
$this->reorderList($list, $index-1);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the index on the given list of ACEs.
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function isWithinBounds(array &$list, $index)
|
||||
{
|
||||
// No count()-1, the count is one ahead of index, and could create the next valid entry!
|
||||
if ($index < 0 or $index > count($list)) {
|
||||
throw new \OutOfBoundsException(sprintf('The index must be in the interval [0, %d].', count($list)));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the index for existence in the given list.
|
||||
*
|
||||
* @throws \OutOfBoundsException
|
||||
*
|
||||
* @param array $list
|
||||
* @param $index
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function validateIndex(array &$list, $index)
|
||||
{
|
||||
if (!isset($list[$index])) {
|
||||
throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given field to be present.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @param array $list
|
||||
* @param string $field
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function validateField(array &$list, $field)
|
||||
{
|
||||
if (!isset($list[$field])) {
|
||||
throw new \InvalidArgumentException(sprintf('The given field "%s" does not exist.', $field));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order the given list to have numeric indexes from 0..x
|
||||
*
|
||||
* @param array $list
|
||||
* @param int $index The right boundary to which the list is valid.
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl $this
|
||||
*/
|
||||
protected function reorderList(array &$list, $index)
|
||||
{
|
||||
$list = array_merge(
|
||||
array_slice($list, 0, $index+1), // +1 to get length
|
||||
array_splice($list, $index+1) // +1 to get first index to re-order
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ACL Entry.
|
||||
*
|
||||
* @param int $mask
|
||||
* @param int $index
|
||||
* @param \Symfony\Component\Security\Acl\Model\SecurityIdentityInterface $securityIdentity
|
||||
* @param string $strategy
|
||||
* @param bool $granting
|
||||
* @param string $field
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\Entry|\Propel\PropelBundle\Security\Acl\Domain\FieldEntry
|
||||
*/
|
||||
protected function createAce($mask, $index, SecurityIdentityInterface $securityIdentity, $strategy = null, $granting = true, $field = null)
|
||||
{
|
||||
if (!is_int($mask)) {
|
||||
throw new \InvalidArgumentException('The given mask is not valid. Please provide an integer.');
|
||||
}
|
||||
|
||||
// Compatibility with default implementation
|
||||
if (null === $strategy) {
|
||||
if (true === $granting) {
|
||||
$strategy = PermissionGrantingStrategy::ALL;
|
||||
} else {
|
||||
$strategy = PermissionGrantingStrategy::ANY;
|
||||
}
|
||||
}
|
||||
|
||||
$model = new ModelEntry();
|
||||
$model
|
||||
->setAceOrder($index)
|
||||
->setMask($mask)
|
||||
->setGrantingStrategy($strategy)
|
||||
->setGranting($granting)
|
||||
->setSecurityIdentity(SecurityIdentity::fromAclIdentity($securityIdentity))
|
||||
;
|
||||
|
||||
if (null !== $field) {
|
||||
$model->setFieldName($field);
|
||||
|
||||
return new FieldEntry($model, $this);
|
||||
}
|
||||
|
||||
return new Entry($model, $this);
|
||||
}
|
||||
}
|
340
Security/Acl/MutableAclProvider.php
Normal file
340
Security/Acl/MutableAclProvider.php
Normal file
|
@ -0,0 +1,340 @@
|
|||
<?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\Security\Acl;
|
||||
|
||||
use Propel\Runtime\ActiveQuery\Criteria;
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Propel\Runtime\Connection\ConnectionInterface;
|
||||
use Propel\Runtime\Propel;
|
||||
use Propel\Runtime\ServiceContainer\ServiceContainerInterface;
|
||||
|
||||
use Propel\PropelBundle\Model\Acl\Entry as ModelEntry;
|
||||
use Propel\PropelBundle\Model\Acl\Map\EntryTableMap;
|
||||
use Propel\PropelBundle\Model\Acl\EntryQuery;
|
||||
use Propel\PropelBundle\Model\Acl\SecurityIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentity;
|
||||
use Propel\PropelBundle\Model\Acl\ObjectIdentityQuery;
|
||||
|
||||
use Propel\PropelBundle\Security\Acl\Domain\Acl;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\MutableAcl;
|
||||
use Propel\PropelBundle\Security\Acl\Domain\Entry;
|
||||
|
||||
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
|
||||
use Symfony\Component\Security\Acl\Exception\Exception as AclException;
|
||||
|
||||
use Symfony\Component\Security\Acl\Model\AclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\EntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
|
||||
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
|
||||
use Symfony\Component\Security\Acl\Model\MutableAclInterface;
|
||||
use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface;
|
||||
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
|
||||
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
|
||||
|
||||
/**
|
||||
* An implementation of the MutableAclProviderInterface using Propel ORM.
|
||||
*
|
||||
* @author Toni Uebernickel <tuebernickel@gmail.com>
|
||||
*/
|
||||
class MutableAclProvider extends AclProvider implements MutableAclProviderInterface
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
||||
* @param ConnectionInterface $connection
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclCacheInterface $cache
|
||||
*/
|
||||
public function __construct(PermissionGrantingStrategyInterface $permissionGrantingStrategy, ConnectionInterface $connection = null, AclCacheInterface $cache = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if (null === $connection) {
|
||||
$connection = Propel::getConnection(EntryTableMap::DATABASE_NAME, ServiceContainerInterface::CONNECTION_WRITE);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
parent::__construct($permissionGrantingStrategy, $connection, $cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ACL for the given object identity.
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException When there already is an ACL for the given object identity.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||
*/
|
||||
public function createAcl(ObjectIdentityInterface $objectIdentity)
|
||||
{
|
||||
$entries = EntryQuery::create()->findByAclIdentity($objectIdentity, array(), $this->connection);
|
||||
if (count($entries)) {
|
||||
throw new AclAlreadyExistsException('An ACL for the given object identity already exists, find and update that one.');
|
||||
}
|
||||
|
||||
$objIdentity = ObjectIdentityQuery::create()
|
||||
->filterByAclObjectIdentity($objectIdentity, $this->connection)
|
||||
->findOneOrCreate($this->connection)
|
||||
;
|
||||
|
||||
if ($objIdentity->isNew()) {
|
||||
// This is safe to do, it makes the ID available and does not affect changes to any ACL.
|
||||
$objIdentity->save($this->connection);
|
||||
}
|
||||
|
||||
return $this->getAcl($entries, $objectIdentity, array(), null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the ACL for a given object identity.
|
||||
*
|
||||
* This will automatically trigger a delete for any child ACLs. If you don't
|
||||
* want child ACLs to be deleted, you will have to set their parent ACL to null.
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\Exception
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteAcl(ObjectIdentityInterface $objectIdentity)
|
||||
{
|
||||
try {
|
||||
$objIdentity = ObjectIdentityQuery::create()->findOneByAclObjectIdentity($objectIdentity, $this->connection);
|
||||
if (null === $objIdentity) {
|
||||
// No object identity, no ACL, so deletion is successful (expected result is given).
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->connection->beginTransaction();
|
||||
|
||||
// Retrieve all class and class-field ACEs, if any.
|
||||
$aces = EntryQuery::create()->findByAclIdentity($objectIdentity, array(), $this->connection);
|
||||
if (count($aces)) {
|
||||
// In case this is the last of its kind, delete the class and class-field ACEs.
|
||||
$count = ObjectIdentityQuery::create()->filterByClassId($objIdentity->getClassId())->count($this->connection);
|
||||
if (1 === $count) {
|
||||
$aces->delete($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
throw new AclException('An error occurred while deleting the ACL.', 1, $e);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists any changes which were made to the ACL, or any associated access control entries.
|
||||
*
|
||||
* Changes to parent ACLs are not persisted.
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Acl\Exception\Exception
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\MutableAclInterface $acl
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function updateAcl(MutableAclInterface $acl)
|
||||
{
|
||||
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();
|
||||
|
||||
$keepEntries = array_merge(
|
||||
$this->persistAcl($acl->getClassAces(), $objectIdentity),
|
||||
$this->persistAcl($acl->getObjectAces(), $objectIdentity, true)
|
||||
);
|
||||
|
||||
foreach ($acl->getFields() as $eachField) {
|
||||
$keepEntries = array_merge($keepEntries,
|
||||
$this->persistAcl($acl->getClassFieldAces($eachField), $objectIdentity),
|
||||
$this->persistAcl($acl->getObjectFieldAces($eachField), $objectIdentity, true)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($modelEntries as &$eachEntry) {
|
||||
if (!in_array($eachEntry->getId(), $keepEntries)) {
|
||||
$eachEntry->delete($this->connection);
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $acl->getParentAcl()) {
|
||||
$objectIdentity
|
||||
->setParentObjectIdentityId(null)
|
||||
->save($this->connection)
|
||||
;
|
||||
} else {
|
||||
$objectIdentity
|
||||
->setParentObjectIdentityId($acl->getParentAcl()->getId())
|
||||
->save($this->connection)
|
||||
;
|
||||
}
|
||||
|
||||
$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) {
|
||||
$this->connection->rollBack();
|
||||
|
||||
throw new AclException('An error occurred while updating the ACL.', 0, $e);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the given ACEs.
|
||||
*
|
||||
* @param array $accessControlEntries
|
||||
* @param \Propel\PropelBundle\Model\Acl\ObjectIdentity $objectIdentity
|
||||
* @param bool $object
|
||||
*
|
||||
* @return array The IDs of the persisted ACEs.
|
||||
*/
|
||||
protected function persistAcl(array $accessControlEntries, ObjectIdentity $objectIdentity, $object = false)
|
||||
{
|
||||
$entries = array();
|
||||
|
||||
/* @var $eachAce \Symfony\Component\Security\Acl\Model\EntryInterface */
|
||||
foreach ($accessControlEntries as $order => $eachAce) {
|
||||
// If the given ACE has never been persisted, create a new one.
|
||||
if (null === $entry = $this->getPersistedAce($eachAce, $objectIdentity, $object)) {
|
||||
$entry = ModelEntry::fromAclEntry($eachAce);
|
||||
}
|
||||
|
||||
if (in_array($entry->getId(), $entries)) {
|
||||
$entry = ModelEntry::fromAclEntry($eachAce);
|
||||
}
|
||||
|
||||
// Apply possible changes from local ACE.
|
||||
$entry
|
||||
->setAceOrder($order)
|
||||
->setAclClass($objectIdentity->getAclClass())
|
||||
->setMask($eachAce->getMask())
|
||||
;
|
||||
|
||||
if ($eachAce instanceof AuditableEntryInterface) {
|
||||
if (is_bool($eachAce->isAuditSuccess())) {
|
||||
$entry->setAuditSuccess($eachAce->isAuditSuccess());
|
||||
}
|
||||
|
||||
if (is_bool($eachAce->isAuditFailure())) {
|
||||
$entry->setAuditFailure($eachAce->isAuditFailure());
|
||||
}
|
||||
}
|
||||
|
||||
if (true === $object) {
|
||||
$entry->setObjectIdentity($objectIdentity);
|
||||
}
|
||||
|
||||
$entry->save($this->connection);
|
||||
|
||||
$entries[] = $entry->getId();
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the persisted model for the given ACE.
|
||||
*
|
||||
* If none is given, null is returned.
|
||||
*
|
||||
* @param \Symfony\Component\Security\Acl\Model\EntryInterface $ace
|
||||
*
|
||||
* @return \Propel\PropelBundle\Model\Acl\Entry|null
|
||||
*/
|
||||
protected function getPersistedAce(EntryInterface $ace, ObjectIdentity $objectIdentity, $object = false)
|
||||
{
|
||||
if (null !== $ace->getId() and null !== $entry = EntryQuery::create()->findPk($ace->getId(), $this->connection)) {
|
||||
$entry->reload(true, $this->connection);
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/*
|
||||
* The id is not set, but there may be an ACE in the database.
|
||||
*
|
||||
* This happens if the ACL has created new ACEs, but was not reloaded.
|
||||
* We try to retrieve one by the unique key.
|
||||
*/
|
||||
$ukQuery = EntryQuery::create()
|
||||
->filterByAclClass($objectIdentity->getAclClass($this->connection))
|
||||
->filterBySecurityIdentity(SecurityIdentity::fromAclIdentity($ace->getSecurityIdentity(), $this->connection))
|
||||
;
|
||||
|
||||
if (true === $object) {
|
||||
$ukQuery->filterByObjectIdentity($objectIdentity);
|
||||
} else {
|
||||
$ukQuery->filterByObjectIdentityId(null, Criteria::ISNULL);
|
||||
}
|
||||
|
||||
if ($ace instanceof FieldEntryInterface) {
|
||||
$ukQuery->filterByFieldName($ace->getField());
|
||||
} else {
|
||||
$ukQuery->filterByFieldName(null, Criteria::ISNULL);
|
||||
}
|
||||
|
||||
return $ukQuery->findOne($this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ACL for this provider.
|
||||
*
|
||||
* @param ObjectCollection $collection
|
||||
* @param \Symfony\Component\Security\Acl\Model\ObjectIdentityInterface $objectIdentity
|
||||
* @param array $loadedSecurityIdentities
|
||||
* @param \Symfony\Component\Security\Acl\Model\AclInterface $parentAcl
|
||||
* @param bool $inherited
|
||||
*
|
||||
* @return \Propel\PropelBundle\Security\Acl\Domain\MutableAcl
|
||||
*/
|
||||
protected function getAcl(ObjectCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true)
|
||||
{
|
||||
return new MutableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection);
|
||||
}
|
||||
}
|
103
Security/User/PropelUserProvider.php
Normal file
103
Security/User/PropelUserProvider.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Propel\PropelBundle\Security\User;
|
||||
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||
|
||||
/**
|
||||
* Provides easy to use provisioning for Propel model users.
|
||||
*
|
||||
* @author William DURAND <william.durand1@gmail.com>
|
||||
*/
|
||||
class PropelUserProvider implements UserProviderInterface
|
||||
{
|
||||
/**
|
||||
* A Model class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* A Query class name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $queryClass;
|
||||
|
||||
/**
|
||||
* A property to use to retrieve the user.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $property;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param string $class The User model class.
|
||||
* @param string|null $property The property to use to retrieve a user.
|
||||
*/
|
||||
public function __construct($class, $property = null)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->queryClass = $class.'Query';
|
||||
$this->property = $property;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadUserByUsername($username)
|
||||
{
|
||||
$queryClass = $this->queryClass;
|
||||
$query = $queryClass::create();
|
||||
|
||||
if (null !== $this->property) {
|
||||
$filter = 'filterBy'.ucfirst($this->property);
|
||||
$query->$filter($username);
|
||||
} else {
|
||||
$query->filterByUsername($username);
|
||||
}
|
||||
|
||||
if (null === $user = $query->findOne()) {
|
||||
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function refreshUser(UserInterface $user)
|
||||
{
|
||||
if (!$user instanceof $this->class) {
|
||||
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
|
||||
}
|
||||
|
||||
$queryClass = $this->queryClass;
|
||||
|
||||
return $queryClass::create()->findPk($user->getPrimaryKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsClass($class)
|
||||
{
|
||||
return $class === $this->class;
|
||||
}
|
||||
}
|
13
Tests/Fixtures/Model/User.php
Normal file
13
Tests/Fixtures/Model/User.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Propel\PropelBundle\Tests\Fixtures\Model;
|
||||
|
||||
use Propel\PropelBundle\Tests\Fixtures\Model\Base\User as BaseUser;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
class User extends BaseUser implements UserInterface
|
||||
{
|
||||
public function eraseCredentials()
|
||||
{
|
||||
}
|
||||
}
|
63
Tests/Security/User/PropelUserProviderTest.php
Normal file
63
Tests/Security/User/PropelUserProviderTest.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?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\Security\User;
|
||||
|
||||
use Propel\PropelBundle\Security\User\PropelUserProvider;
|
||||
use Propel\PropelBundle\Tests\Fixtures\Model\User;
|
||||
use Propel\PropelBundle\Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @author William Durand <william.durand1@gmail.com>
|
||||
*/
|
||||
class PropelUserProviderTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$schema = <<<SCHEMA
|
||||
<database name="users" defaultIdMethod="native" namespace="Propel\\PropelBundle\\Tests\\Fixtures\\Model">
|
||||
<table name="user">
|
||||
<column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
|
||||
<column name="username" type="varchar" size="255" primaryString="true" />
|
||||
<column name="algorithm" type="varchar" size="50" />
|
||||
<column name="salt" type="varchar" size="255" />
|
||||
<column name="password" type="varchar" size="255" />
|
||||
<column name="expires_at" type="timestamp" />
|
||||
<column name="roles" type="array" />
|
||||
</table>
|
||||
</database>
|
||||
SCHEMA;
|
||||
|
||||
$builder = new QuickBuilder();
|
||||
$builder->setSchema($schema);
|
||||
$classTargets = null;
|
||||
|
||||
$this->con = $builder->build($dsn = null, $user = null, $pass = null, $adapter = null, $classTargets);
|
||||
}
|
||||
|
||||
public function testRefreshUserGetsUserByPrimaryKey()
|
||||
{
|
||||
$user1 = new User();
|
||||
$user1->setUsername('user1');
|
||||
$user1->save();
|
||||
|
||||
$user2 = new User();
|
||||
$user2->setUsername('user2');
|
||||
$user2->save();
|
||||
|
||||
$provider = new PropelUserProvider('Propel\PropelBundle\Tests\Fixtures\Model\User', 'username');
|
||||
|
||||
// try to change the user identity
|
||||
$user1->setUsername('user2');
|
||||
|
||||
$resultUser = $provider->refreshUser($user1);
|
||||
$this->assertSame($user1, $resultUser);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue