vendor/symfony/src/Symfony/Component/Security/Acl/Domain/Acl.php
changeset 0 7f95f8617b0b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/symfony/src/Symfony/Component/Security/Acl/Domain/Acl.php	Sat Sep 24 15:40:41 2011 +0200
@@ -0,0 +1,679 @@
+<?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 Symfony\Component\Security\Acl\Domain;
+
+use Doctrine\Common\NotifyPropertyChanged;
+use Doctrine\Common\PropertyChangedListener;
+use Symfony\Component\Security\Acl\Model\AclInterface;
+use Symfony\Component\Security\Acl\Model\AuditableAclInterface;
+use Symfony\Component\Security\Acl\Model\EntryInterface;
+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;
+
+
+/**
+ * An ACL implementation.
+ *
+ * Each object identity has exactly one associated ACL. Each ACL can have four
+ * different types of ACEs (class ACEs, object ACEs, class field ACEs, object field
+ * ACEs).
+ *
+ * You should not iterate over the ACEs yourself, but instead use isGranted(),
+ * or isFieldGranted(). These will utilize an implementation of PermissionGrantingStrategy
+ * internally.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class Acl implements AuditableAclInterface, NotifyPropertyChanged
+{
+    private $parentAcl;
+    private $permissionGrantingStrategy;
+    private $objectIdentity;
+    private $classAces;
+    private $classFieldAces;
+    private $objectAces;
+    private $objectFieldAces;
+    private $id;
+    private $loadedSids;
+    private $entriesInheriting;
+    private $listeners;
+
+    /**
+     * Constructor
+     *
+     * @param integer                             $id
+     * @param ObjectIdentityInterface             $objectIdentity
+     * @param PermissionGrantingStrategyInterface $permissionGrantingStrategy
+     * @param array                               $loadedSids
+     * @param Boolean                             $entriesInheriting
+     * @return void
+     */
+    public function __construct($id, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSids = array(), $entriesInheriting)
+    {
+        $this->id = $id;
+        $this->objectIdentity = $objectIdentity;
+        $this->permissionGrantingStrategy = $permissionGrantingStrategy;
+        $this->loadedSids = $loadedSids;
+        $this->entriesInheriting = $entriesInheriting;
+        $this->parentAcl = null;
+        $this->classAces = array();
+        $this->classFieldAces = array();
+        $this->objectAces = array();
+        $this->objectFieldAces = array();
+        $this->listeners = array();
+    }
+
+    /**
+     * Adds a property changed listener
+     *
+     * @param PropertyChangedListener $listener
+     * @return void
+     */
+    public function addPropertyChangedListener(PropertyChangedListener $listener)
+    {
+        $this->listeners[] = $listener;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function deleteClassAce($index)
+    {
+        $this->deleteAce('classAces', $index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function deleteClassFieldAce($index, $field)
+    {
+        $this->deleteFieldAce('classFieldAces', $index, $field);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function deleteObjectAce($index)
+    {
+        $this->deleteAce('objectAces', $index);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function deleteObjectFieldAce($index, $field)
+    {
+        $this->deleteFieldAce('objectFieldAces', $index, $field);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassAces()
+    {
+        return $this->classAces;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getClassFieldAces($field)
+    {
+        return isset($this->classFieldAces[$field])? $this->classFieldAces[$field] : array();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getObjectAces()
+    {
+        return $this->objectAces;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getObjectFieldAces($field)
+    {
+        return isset($this->objectFieldAces[$field]) ? $this->objectFieldAces[$field] : array();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getId()
+    {
+        return $this->id;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getObjectIdentity()
+    {
+        return $this->objectIdentity;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getParentAcl()
+    {
+        return $this->parentAcl;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function insertClassAce(SecurityIdentityInterface $sid, $mask, $index = 0, $granting = true, $strategy = null)
+    {
+        $this->insertAce('classAces', $index, $mask, $sid, $granting, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function insertClassFieldAce($field, SecurityIdentityInterface $sid, $mask, $index = 0, $granting = true, $strategy = null)
+    {
+        $this->insertFieldAce('classFieldAces', $index, $field, $mask, $sid, $granting, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function insertObjectAce(SecurityIdentityInterface $sid, $mask, $index = 0, $granting = true, $strategy = null)
+    {
+        $this->insertAce('objectAces', $index, $mask, $sid, $granting, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function insertObjectFieldAce($field, SecurityIdentityInterface $sid, $mask, $index = 0, $granting = true, $strategy = null)
+    {
+        $this->insertFieldAce('objectFieldAces', $index, $field, $mask, $sid, $granting, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isEntriesInheriting()
+    {
+        return $this->entriesInheriting;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isFieldGranted($field, array $masks, array $securityIdentities, $administrativeMode = false)
+    {
+        return $this->permissionGrantingStrategy->isFieldGranted($this, $field, $masks, $securityIdentities, $administrativeMode);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isGranted(array $masks, array $securityIdentities, $administrativeMode = false)
+    {
+        return $this->permissionGrantingStrategy->isGranted($this, $masks, $securityIdentities, $administrativeMode);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function isSidLoaded($sids)
+    {
+        if (!$this->loadedSids) {
+            return true;
+        }
+
+        if (!is_array($sids)) {
+            $sids = array($sids);
+        }
+
+        foreach ($sids as $sid) {
+            if (!$sid instanceof SecurityIdentityInterface) {
+                throw new \InvalidArgumentException(
+                    '$sid must be an instance of SecurityIdentityInterface.');
+            }
+
+            foreach ($this->loadedSids as $loadedSid) {
+                if ($loadedSid->equals($sid)) {
+                    continue 2;
+                }
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Implementation for the \Serializable interface
+     *
+     * @return string
+     */
+    public function serialize()
+    {
+        return serialize(array(
+            null === $this->parentAcl ? null : $this->parentAcl->getId(),
+            $this->objectIdentity,
+            $this->classAces,
+            $this->classFieldAces,
+            $this->objectAces,
+            $this->objectFieldAces,
+            $this->id,
+            $this->loadedSids,
+            $this->entriesInheriting,
+        ));
+    }
+
+    /**
+     * Implementation for the \Serializable interface
+     *
+     * @param string $serialized
+     * @return void
+     */
+    public function unserialize($serialized)
+    {
+        list($this->parentAcl,
+             $this->objectIdentity,
+             $this->classAces,
+             $this->classFieldAces,
+             $this->objectAces,
+             $this->objectFieldAces,
+             $this->id,
+             $this->loadedSids,
+             $this->entriesInheriting
+        ) = unserialize($serialized);
+
+        $this->listeners = array();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setEntriesInheriting($boolean)
+    {
+        if ($this->entriesInheriting !== $boolean) {
+            $this->onPropertyChanged('entriesInheriting', $this->entriesInheriting, $boolean);
+            $this->entriesInheriting = $boolean;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function setParentAcl(AclInterface $acl)
+    {
+        if (null === $acl->getId()) {
+            throw new \InvalidArgumentException('$acl must have an ID.');
+        }
+
+        if ($this->parentAcl !== $acl) {
+            $this->onPropertyChanged('parentAcl', $this->parentAcl, $acl);
+            $this->parentAcl = $acl;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateClassAce($index, $mask, $strategy = null)
+    {
+        $this->updateAce('classAces', $index, $mask, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateClassFieldAce($index, $field, $mask, $strategy = null)
+    {
+        $this->updateFieldAce('classFieldAces', $index, $field, $mask, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateObjectAce($index, $mask, $strategy = null)
+    {
+        $this->updateAce('objectAces', $index, $mask, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateObjectFieldAce($index, $field, $mask, $strategy = null)
+    {
+        $this->updateFieldAce('objectFieldAces', $index, $field, $mask, $strategy);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateClassAuditing($index, $auditSuccess, $auditFailure)
+    {
+        $this->updateAuditing($this->classAces, $index, $auditSuccess, $auditFailure);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateClassFieldAuditing($index, $field, $auditSuccess, $auditFailure)
+    {
+        if (!isset($this->classFieldAces[$field])) {
+            throw new \InvalidArgumentException(sprintf('There are no ACEs for field "%s".', $field));
+        }
+
+        $this->updateAuditing($this->classFieldAces[$field], $index, $auditSuccess, $auditFailure);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateObjectAuditing($index, $auditSuccess, $auditFailure)
+    {
+        $this->updateAuditing($this->objectAces, $index, $auditSuccess, $auditFailure);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function updateObjectFieldAuditing($index, $field, $auditSuccess, $auditFailure)
+    {
+        if (!isset($this->objectFieldAces[$field])) {
+            throw new \InvalidArgumentException(sprintf('There are no ACEs for field "%s".', $field));
+        }
+
+        $this->updateAuditing($this->objectFieldAces[$field], $index, $auditSuccess, $auditFailure);
+    }
+
+    /**
+     * Deletes an ACE
+     *
+     * @param string $property
+     * @param integer $index
+     * @throws \OutOfBoundsException
+     * @return void
+     */
+    private function deleteAce($property, $index)
+    {
+        $aces =& $this->$property;
+        if (!isset($aces[$index])) {
+            throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
+        }
+
+        $oldValue = $this->$property;
+        unset($aces[$index]);
+        $this->$property = array_values($this->$property);
+        $this->onPropertyChanged($property, $oldValue, $this->$property);
+
+        for ($i=$index,$c=count($this->$property); $i<$c; $i++) {
+            $this->onEntryPropertyChanged($aces[$i], 'aceOrder', $i+1, $i);
+        }
+    }
+
+    /**
+     * Deletes a field-based ACE
+     *
+     * @param string $property
+     * @param integer $index
+     * @param string $field
+     * @throws \OutOfBoundsException
+     * @return void
+     */
+    private function deleteFieldAce($property, $index, $field)
+    {
+        $aces =& $this->$property;
+        if (!isset($aces[$field][$index])) {
+            throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
+        }
+
+        $oldValue = $this->$property;
+        unset($aces[$field][$index]);
+        $aces[$field] = array_values($aces[$field]);
+        $this->onPropertyChanged($property, $oldValue, $this->$property);
+
+        for ($i=$index,$c=count($aces[$field]); $i<$c; $i++) {
+            $this->onEntryPropertyChanged($aces[$field][$i], 'aceOrder', $i+1, $i);
+        }
+    }
+
+    /**
+     * Inserts an ACE
+     *
+     * @param string                    $property
+     * @param integer                   $index
+     * @param integer                   $mask
+     * @param SecurityIdentityInterface $sid
+     * @param Boolean                   $granting
+     * @param string                    $strategy
+     * @throws \OutOfBoundsException
+     * @throws \InvalidArgumentException
+     * @return void
+     */
+    private function insertAce($property, $index, $mask, SecurityIdentityInterface $sid, $granting, $strategy = null)
+    {
+        if ($index < 0 || $index > count($this->$property)) {
+            throw new \OutOfBoundsException(sprintf('The index must be in the interval [0, %d].', count($this->$property)));
+        }
+
+        if (!is_int($mask)) {
+            throw new \InvalidArgumentException('$mask must be an integer.');
+        }
+
+        if (null === $strategy) {
+            if (true === $granting) {
+                $strategy = PermissionGrantingStrategy::ALL;
+            } else {
+                $strategy = PermissionGrantingStrategy::ANY;
+            }
+        }
+
+        $aces =& $this->$property;
+        $oldValue = $this->$property;
+        if (isset($aces[$index])) {
+            $this->$property = array_merge(
+                array_slice($this->$property, 0, $index),
+                array(true),
+                array_slice($this->$property, $index)
+            );
+
+            for ($i=$index,$c=count($this->$property)-1; $i<$c; $i++) {
+                $this->onEntryPropertyChanged($aces[$i+1], 'aceOrder', $i, $i+1);
+            }
+        }
+
+        $aces[$index] = new Entry(null, $this, $sid, $strategy, $mask, $granting, false, false);
+        $this->onPropertyChanged($property, $oldValue, $this->$property);
+    }
+
+    /**
+     * Inserts a field-based ACE
+     *
+     * @param string                    $property
+     * @param integer                   $index
+     * @param string                    $field
+     * @param integer                   $mask
+     * @param SecurityIdentityInterface $sid
+     * @param Boolean                   $granting
+     * @param string                    $strategy
+     * @throws \InvalidArgumentException
+     * @throws \OutOfBoundsException
+     * @return void
+     */
+    private function insertFieldAce($property, $index, $field, $mask, SecurityIdentityInterface $sid, $granting, $strategy = null)
+    {
+        if (0 === strlen($field)) {
+            throw new \InvalidArgumentException('$field cannot be empty.');
+        }
+
+        if (!is_int($mask)) {
+            throw new \InvalidArgumentException('$mask must be an integer.');
+        }
+
+        if (null === $strategy) {
+            if (true === $granting) {
+                $strategy = PermissionGrantingStrategy::ALL;
+            } else {
+                $strategy = PermissionGrantingStrategy::ANY;
+            }
+        }
+
+        $aces =& $this->$property;
+        if (!isset($aces[$field])) {
+            $aces[$field] = array();
+        }
+
+        if ($index < 0 || $index > count($aces[$field])) {
+            throw new \OutOfBoundsException(sprintf('The index must be in the interval [0, %d].', count($this->$property)));
+        }
+
+        $oldValue = $aces;
+        if (isset($aces[$field][$index])) {
+            $aces[$field] = array_merge(
+                array_slice($aces[$field], 0, $index),
+                array(true),
+                array_slice($aces[$field], $index)
+            );
+
+            for ($i=$index,$c=count($aces[$field])-1; $i<$c; $i++) {
+                $this->onEntryPropertyChanged($aces[$field][$i+1], 'aceOrder', $i, $i+1);
+            }
+        }
+
+        $aces[$field][$index] = new FieldEntry(null, $this, $field, $sid, $strategy, $mask, $granting, false, false);
+        $this->onPropertyChanged($property, $oldValue, $this->$property);
+    }
+
+    /**
+     * Updates an ACE
+     *
+     * @param string $property
+     * @param integer $index
+     * @param integer $mask
+     * @param string $strategy
+     * @throws \OutOfBoundsException
+     * @return void
+     */
+    private function updateAce($property, $index, $mask, $strategy = null)
+    {
+        $aces =& $this->$property;
+        if (!isset($aces[$index])) {
+            throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
+        }
+
+        $ace = $aces[$index];
+        if ($mask !== $oldMask = $ace->getMask()) {
+            $this->onEntryPropertyChanged($ace, 'mask', $oldMask, $mask);
+            $ace->setMask($mask);
+        }
+        if (null !== $strategy && $strategy !== $oldStrategy = $ace->getStrategy()) {
+            $this->onEntryPropertyChanged($ace, 'strategy', $oldStrategy, $strategy);
+            $ace->setStrategy($strategy);
+        }
+    }
+
+    /**
+     * Updates auditing for an ACE
+     *
+     * @param array $aces
+     * @param integer $index
+     * @param Boolean $auditSuccess
+     * @param Boolean $auditFailure
+     * @throws \OutOfBoundsException
+     * @return void
+     */
+    private function updateAuditing(array &$aces, $index, $auditSuccess, $auditFailure)
+    {
+        if (!isset($aces[$index])) {
+            throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
+        }
+
+        if ($auditSuccess !== $aces[$index]->isAuditSuccess()) {
+            $this->onEntryPropertyChanged($aces[$index], 'auditSuccess', !$auditSuccess, $auditSuccess);
+            $aces[$index]->setAuditSuccess($auditSuccess);
+        }
+
+        if ($auditFailure !== $aces[$index]->isAuditFailure()) {
+            $this->onEntryPropertyChanged($aces[$index], 'auditFailure', !$auditFailure, $auditFailure);
+            $aces[$index]->setAuditFailure($auditFailure);
+        }
+    }
+
+    /**
+     * Updates a field-based ACE
+     *
+     * @param string $property
+     * @param integer $index
+     * @param string $field
+     * @param integer $mask
+     * @param string $strategy
+     * @throws \InvalidArgumentException
+     * @throws \OutOfBoundsException
+     * @return void
+     */
+    private function updateFieldAce($property, $index, $field, $mask, $strategy = null)
+    {
+        if (0 === strlen($field)) {
+            throw new \InvalidArgumentException('$field cannot be empty.');
+        }
+
+        $aces =& $this->$property;
+        if (!isset($aces[$field][$index])) {
+            throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
+        }
+
+        $ace = $aces[$field][$index];
+        if ($mask !== $oldMask = $ace->getMask()) {
+            $this->onEntryPropertyChanged($ace, 'mask', $oldMask, $mask);
+            $ace->setMask($mask);
+        }
+        if (null !== $strategy && $strategy !== $oldStrategy = $ace->getStrategy()) {
+            $this->onEntryPropertyChanged($ace, 'strategy', $oldStrategy, $strategy);
+            $ace->setStrategy($strategy);
+        }
+    }
+
+    /**
+     * Called when a property of the ACL changes
+     *
+     * @param string $name
+     * @param mixed $oldValue
+     * @param mixed $newValue
+     * @return void
+     */
+    private function onPropertyChanged($name, $oldValue, $newValue)
+    {
+        foreach ($this->listeners as $listener) {
+            $listener->propertyChanged($this, $name, $oldValue, $newValue);
+        }
+    }
+
+    /**
+     * Called when a property of an ACE associated with this ACL changes
+     *
+     * @param EntryInterface $entry
+     * @param string         $name
+     * @param mixed          $oldValue
+     * @param mixed          $newValue
+     * @return void
+     */
+    private function onEntryPropertyChanged(EntryInterface $entry, $name, $oldValue, $newValue)
+    {
+        foreach ($this->listeners as $listener) {
+            $listener->propertyChanged($entry, $name, $oldValue, $newValue);
+        }
+    }
+}