/** * Gets the ACLs that belong to the given object identities * * We have to implement this method due a bug in AclProvider::findAcls: * when $oids array length > AclProvider::MAX_BATCH_SIZE and no any ACLs were found for any bath, the findAcls * method throws AclNotFoundException rather than continue loading ACLs for other batched and throw * this exception only when no any ACLs found for all batches. But if at least one ACL (but not all) was found * this method should throw NotAllAclsFoundException. * * @param OID[] $oids * @param SID[] $sids * @return \SplObjectStorage mapping the passed object identities to ACLs * @throws AclNotFoundException * @throws NotAllAclsFoundException */ protected function doFindAcls(array $oids, array $sids) { // split object identities to batches (batch size must be less than or equal AclProvider::MAX_BATCH_SIZE) $oidsBatches = array(); $batchIndex = 0; $oidsBatches[$batchIndex] = array(); $index = 0; foreach ($oids as $oid) { /** * We can not use AclProvider::MAX_BATCH_SIZE of Symfony ACL due to a bug check in the cache */ if ($index >= self::MAX_BATCH_SIZE) { $index = 0; $batchIndex++; } $oidsBatches[$batchIndex][] = $oid; $index++; } $result = null; foreach ($oidsBatches as $oidsBatch) { try { $acls = $this->aclProvider->findAcls($oidsBatch, $sids); if ($result === null) { $result = $acls; } else { foreach ($acls as $aclOid) { $result->attach($aclOid, $acls->offsetGet($aclOid)); } } } catch (AclNotFoundException $ex) { if ($ex instanceof NotAllAclsFoundException) { if ($result === null) { $result = $ex->getPartialResult(); } else { $partialResult = $ex->getPartialResult(); foreach ($partialResult as $aclOid) { $result->attach($aclOid, $partialResult->offsetGet($aclOid)); } } } else { if ($result === null) { $result = new \SplObjectStorage(); } } } } // check that we got ACLs for all the identities foreach ($oids as $oid) { if (!$result->contains($oid)) { if (1 === count($oids)) { throw new AclNotFoundException(sprintf('No ACL found for %s.', $oid)); } $partialResultEx = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.'); $partialResultEx->setPartialResult($result); throw $partialResultEx; } } return $result; }
/** * {@inheritDoc} */ public function findAcls(array $oids, array $sids = array()) { $result = new \SplObjectStorage(); $currentBatch = array(); $oidLookup = array(); for ($i = 0, $c = count($oids); $i < $c; $i++) { $oid = $oids[$i]; $oidLookupKey = $oid->getIdentifier() . $oid->getType(); $oidLookup[$oidLookupKey] = $oid; $aclFound = false; // check if result already contains an ACL if ($result->contains($oid)) { $aclFound = true; } // check if this ACL has already been hydrated if (!$aclFound && isset($this->loadedAcls[$oid->getType()][$oid->getIdentifier()])) { $acl = $this->loadedAcls[$oid->getType()][$oid->getIdentifier()]; if (!$acl->isSidLoaded($sids)) { // FIXME: we need to load ACEs for the missing SIDs. This is never // reached by the default implementation, since we do not // filter by SID throw new \RuntimeException('This is not supported by the default implementation.'); } else { $result->attach($oid, $acl); $aclFound = true; } } // check if we can locate the ACL in the cache if (!$aclFound && null !== $this->aclCache) { $acl = $this->aclCache->getFromCacheByIdentity($oid); if (null !== $acl) { if ($acl->isSidLoaded($sids)) { // check if any of the parents has been loaded since we need to // ensure that there is only ever one ACL per object identity $parentAcl = $acl->getParentAcl(); while (null !== $parentAcl) { $parentOid = $parentAcl->getObjectIdentity(); if (isset($this->loadedAcls[$parentOid->getType()][$parentOid->getIdentifier()])) { $acl->setParentAcl($this->loadedAcls[$parentOid->getType()][$parentOid->getIdentifier()]); break; } else { $this->loadedAcls[$parentOid->getType()][$parentOid->getIdentifier()] = $parentAcl; $this->updateAceIdentityMap($parentAcl); } $parentAcl = $parentAcl->getParentAcl(); } $this->loadedAcls[$oid->getType()][$oid->getIdentifier()] = $acl; $this->updateAceIdentityMap($acl); $result->attach($oid, $acl); $aclFound = true; } else { $this->aclCache->evictFromCacheByIdentity($oid); foreach ($this->findChildren($oid) as $childOid) { $this->aclCache->evictFromCacheByIdentity($childOid); } } } } // looks like we have to load the ACL from the database if (!$aclFound) { $currentBatch[] = $oid; } // Is it time to load the current batch? if ((self::MAX_BATCH_SIZE === count($currentBatch) || $i + 1 === $c) && count($currentBatch) > 0) { $loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup); foreach ($loadedBatch as $loadedOid) { $loadedAcl = $loadedBatch->offsetGet($loadedOid); if (null !== $this->aclCache) { $this->aclCache->putInCache($loadedAcl); } if (isset($oidLookup[$loadedOid->getIdentifier() . $loadedOid->getType()])) { $result->attach($loadedOid, $loadedAcl); } } $currentBatch = array(); } } // check that we got ACLs for all the identities foreach ($oids as $oid) { if (!$result->contains($oid)) { if (1 === count($oids)) { throw new AclNotFoundException(sprintf('No ACL found for %s.', $oid)); } $partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.'); $partialResultException->setPartialResult($result); throw $partialResultException; } } return $result; }
/** * @param array $src * @throws NotAllAclsFoundException * @return \SplObjectStorage */ public static function getAcls(array $src) { $isPartial = false; $acls = new \SplObjectStorage(); foreach ($src as $item) { if ($item['acl'] !== null) { $acls->attach($item['oid'], $item['acl']); } else { $isPartial = true; } } if ($isPartial) { $ex = new NotAllAclsFoundException(); $ex->setPartialResult($acls); throw $ex; } return $acls; }