mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-17 15:03:25 +00:00
Merge pull request #1646 from bburnichon/improvement/avoid-cache-overload
Avoid many calls to cache layer
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
/**
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2014 Alchemy
|
||||
* (c) 2005-2016 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
@@ -11,37 +10,63 @@
|
||||
|
||||
namespace Alchemy\Phrasea\Core\Configuration;
|
||||
|
||||
use Alchemy\Phrasea\Cache\Cache;
|
||||
use Alchemy\Phrasea\Model\Entities\Collection;
|
||||
use Alchemy\Phrasea\Model\Entities\Databox;
|
||||
use Assert\Assertion;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class AccessRestriction
|
||||
{
|
||||
private $conf;
|
||||
private $appbox;
|
||||
private $logger;
|
||||
private $cache;
|
||||
/**
|
||||
* @var PropertyAccess
|
||||
*/
|
||||
private $propertyAccess;
|
||||
|
||||
public function __construct(Cache $cache, PropertyAccess $conf, \appbox $appbox, LoggerInterface $logger)
|
||||
/**
|
||||
* @var \appbox
|
||||
*/
|
||||
private $appbox;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $loaded = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $restricted = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $availableDataboxes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $availableCollections = [];
|
||||
|
||||
public function __construct(PropertyAccess $propertyAccess, \appbox $appbox, LoggerInterface $logger)
|
||||
{
|
||||
$this->conf = $conf;
|
||||
$this->propertyAccess = $propertyAccess;
|
||||
$this->appbox = $appbox;
|
||||
$this->logger = $logger;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a configuration is set.
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isRestricted()
|
||||
{
|
||||
$this->load();
|
||||
|
||||
return $this->cache->fetch('restricted');
|
||||
return $this->restricted;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +74,7 @@ class AccessRestriction
|
||||
*
|
||||
* @param \databox $databox
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isDataboxAvailable(\databox $databox)
|
||||
{
|
||||
@@ -57,7 +82,7 @@ class AccessRestriction
|
||||
return true;
|
||||
}
|
||||
|
||||
return in_array($databox->get_sbas_id(), $this->cache->fetch('available_databoxes'), true);
|
||||
return in_array($databox->get_sbas_id(), $this->availableDataboxes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,7 +97,7 @@ class AccessRestriction
|
||||
return $databoxes;
|
||||
}
|
||||
|
||||
$available = array_flip($this->cache->fetch('available_databoxes'));
|
||||
$available = array_flip($this->availableDataboxes);
|
||||
|
||||
return array_filter($databoxes, function (\databox $databox) use ($available) {
|
||||
return isset($available[$databox->get_sbas_id()]);
|
||||
@@ -84,7 +109,7 @@ class AccessRestriction
|
||||
*
|
||||
* @param \collection $collection
|
||||
*
|
||||
* @return Boolean
|
||||
* @return bool
|
||||
*/
|
||||
public function isCollectionAvailable(\collection $collection)
|
||||
{
|
||||
@@ -92,30 +117,31 @@ class AccessRestriction
|
||||
return true;
|
||||
}
|
||||
|
||||
$availableCollections = $this->cache->fetch('available_collections_'.$collection->get_databox()->get_sbas_id()) ?: [];
|
||||
$availableCollections = isset($this->availableCollections[$collection->get_sbas_id()])
|
||||
? $this->availableCollections[$collection->get_sbas_id()] : [];
|
||||
|
||||
return in_array($collection->get_base_id(), $availableCollections, true);
|
||||
}
|
||||
|
||||
private function load()
|
||||
{
|
||||
if ($this->cache->fetch('loaded')) {
|
||||
if ($this->loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cache->save('loaded', true);
|
||||
$this->loaded = true;
|
||||
|
||||
$allowedDataboxIds = array_map(function ($dbConf) {
|
||||
return $dbConf['id'];
|
||||
}, $this->conf->get('databoxes', []));
|
||||
}, $this->propertyAccess->get('databoxes', []));
|
||||
|
||||
if (count($allowedDataboxIds) === 0) {
|
||||
$this->cache->save('restricted', false);
|
||||
$this->restricted = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cache->save('restricted', true);
|
||||
$this->restricted = true;
|
||||
|
||||
$databoxIds = array_map(function (\databox $databox) { return $databox->get_sbas_id(); }, $this->appbox->get_databoxes());
|
||||
$errors = array_diff($allowedDataboxIds, $databoxIds);
|
||||
@@ -124,18 +150,15 @@ class AccessRestriction
|
||||
$this->logger->error(sprintf('Misconfiguration for allowed databoxes : ids %s do not exist', implode(', ', $errors)));
|
||||
}
|
||||
|
||||
$allowedDataboxIds = array_intersect($allowedDataboxIds, $databoxIds);
|
||||
$this->cache->save('available_databoxes', $allowedDataboxIds);
|
||||
$this->availableDataboxes = array_intersect($allowedDataboxIds, $databoxIds);
|
||||
|
||||
$this->loadCollections();
|
||||
}
|
||||
|
||||
private function loadCollections()
|
||||
{
|
||||
$allowedDataboxIds = $this->cache->fetch('available_databoxes');
|
||||
|
||||
foreach ($this->conf->get('databoxes') as $databox) {
|
||||
if (!in_array($databox['id'], $allowedDataboxIds, true)) {
|
||||
foreach ($this->propertyAccess->get('databoxes') as $databox) {
|
||||
if (!in_array($databox['id'], $this->availableDataboxes, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -148,9 +171,7 @@ class AccessRestriction
|
||||
$this->logger->error(sprintf('Misconfiguration for allowed collections : ids %s do not exist', implode(', ', $errors)));
|
||||
}
|
||||
|
||||
$collections = array_intersect($collections, $availableBaseIds);
|
||||
|
||||
$this->cache->save('available_collections_'.$databox['id'], $collections);
|
||||
$this->availableCollections[$databox['id']] = array_intersect($collections, $availableBaseIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -69,7 +69,7 @@ class ConfigurationServiceProvider implements ServiceProviderInterface
|
||||
});
|
||||
|
||||
$app['conf.restrictions'] = $app->share(function (SilexApplication $app) {
|
||||
return new AccessRestriction($app['cache'], $app['conf'], $app->getApplicationBox(), $app['monolog']);
|
||||
return new AccessRestriction($app['conf'], $app->getApplicationBox(), $app['monolog']);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -730,11 +730,7 @@ class ACL implements cache_cacheableInterface
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$ret[$base_id] = collection::getByBaseId($this->app, $base_id);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
$ret[$base_id] = $collection;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -335,7 +335,7 @@ class appbox extends base
|
||||
/**
|
||||
* @return AccessRestriction
|
||||
*/
|
||||
private function getAccessRestriction()
|
||||
public function getAccessRestriction()
|
||||
{
|
||||
return $this->app['conf.restrictions'];
|
||||
}
|
||||
|
@@ -188,52 +188,73 @@ class collection implements ThumbnailedElement, cache_cacheableInterface
|
||||
));
|
||||
}
|
||||
|
||||
$repository = self::getRepository($app, $reference->getDataboxId());
|
||||
$collection = $repository->find($reference->getCollectionId());
|
||||
return self::getAvailableCollection($app, $reference->getDataboxId(), $reference->getCollectionId());
|
||||
}
|
||||
|
||||
if (!$collection) {
|
||||
throw new Exception_Databox_CollectionNotFound(sprintf(
|
||||
"Collection with base_id %s could not be found",
|
||||
$base_id
|
||||
));
|
||||
}
|
||||
/**
|
||||
* @param Application $app
|
||||
* @param databox $databox
|
||||
* @param int $collectionId
|
||||
* @return collection
|
||||
*/
|
||||
public static function getByCollectionId(Application $app, databox $databox, $collectionId)
|
||||
{
|
||||
assert(is_int($collectionId));
|
||||
|
||||
if (!$app['conf.restrictions']->isCollectionAvailable($collection)) {
|
||||
return self::getAvailableCollection($app, $databox->get_sbas_id(), $collectionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Application $app
|
||||
* @return \Alchemy\Phrasea\Core\Configuration\AccessRestriction
|
||||
*/
|
||||
private static function getAccessRestriction(Application $app)
|
||||
{
|
||||
return $app['conf.restrictions'];
|
||||
}
|
||||
|
||||
private static function assertCollectionIsAvailable(Application $app, collection $collection)
|
||||
{
|
||||
if (!self::getAccessRestriction($app)->isCollectionAvailable($collection)) {
|
||||
throw new Exception_Databox_CollectionNotFound(sprintf(
|
||||
'Collection `%d` is not available here.',
|
||||
$collection->get_base_id()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Application $app
|
||||
* @param int $databoxId
|
||||
* @param int $collectionId
|
||||
* @return collection
|
||||
*/
|
||||
private static function getByDataboxIdAndCollectionId(Application $app, $databoxId, $collectionId)
|
||||
{
|
||||
$repository = self::getRepository($app, $databoxId);
|
||||
$collection = $repository->find($collectionId);
|
||||
|
||||
if (!$collection) {
|
||||
throw new Exception_Databox_CollectionNotFound(sprintf(
|
||||
"Collection '%d' on databox '%d' could not be found",
|
||||
$collectionId,
|
||||
$databoxId
|
||||
));
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Application $app
|
||||
* @param databox $databox
|
||||
* @param int $coll_id
|
||||
* @param Application $app
|
||||
* @param int $databoxId
|
||||
* @param int $collectionId
|
||||
* @return collection
|
||||
*/
|
||||
public static function getByCollectionId(Application $app, databox $databox, $coll_id)
|
||||
private static function getAvailableCollection(Application $app, $databoxId, $collectionId)
|
||||
{
|
||||
assert(is_int($coll_id));
|
||||
|
||||
$repository = self::getRepository($app, $databox->get_sbas_id());
|
||||
$collection = $repository->find($coll_id);
|
||||
|
||||
if (!$collection) {
|
||||
throw new Exception_Databox_CollectionNotFound(sprintf(
|
||||
"Collection with collection ID %d could not be found",
|
||||
$coll_id
|
||||
));
|
||||
}
|
||||
|
||||
if (!$app['conf.restrictions']->isCollectionAvailable($collection)) {
|
||||
throw new Exception_Databox_CollectionNotFound(sprintf(
|
||||
'Collection `%d` is not available here.',
|
||||
$collection->get_base_id()
|
||||
));
|
||||
}
|
||||
$collection = self::getByDataboxIdAndCollectionId($app, $databoxId, $collectionId);
|
||||
self::assertCollectionIsAvailable($app, $collection);
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ class AccessRestrictionTest extends \PhraseanetTestCase
|
||||
$conf = new MockArrayConf($conf);
|
||||
$logger = $this->createLoggerMock();
|
||||
|
||||
$restriction = new AccessRestriction(new ArrayCache(), new PropertyAccess($conf), self::$DI['app']['phraseanet.appbox'], $logger);
|
||||
$restriction = new AccessRestriction(new PropertyAccess($conf), self::$DI['app']['phraseanet.appbox'], $logger);
|
||||
$this->assertEquals($restricted, $restriction->isRestricted());
|
||||
|
||||
foreach ($collAccess as $coll) {
|
||||
|
Reference in New Issue
Block a user