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