diff --git a/lib/Alchemy/Phrasea/Cache/Cache.php b/lib/Alchemy/Phrasea/Cache/Cache.php index 04fe604b60..e56bbe5ace 100644 --- a/lib/Alchemy/Phrasea/Cache/Cache.php +++ b/lib/Alchemy/Phrasea/Cache/Cache.php @@ -18,7 +18,7 @@ interface Cache extends DoctrineCache /** * Sets the namespace * - * @param type $namespace + * @param string $namespace */ public function setNamespace($namespace); @@ -53,7 +53,7 @@ interface Cache extends DoctrineCache * @return string The cached data. * @return FALSE, if no cache entry exists for the given id. * - * @throws Alchemy\Phrasea\Cache\Exception if provided key does not exist + * @throws Exception if provided key does not exist */ public function get($key); @@ -61,7 +61,7 @@ interface Cache extends DoctrineCache * Delete multi cache entries * * @param array $keys contains all keys to delete - * @return Alchemy\Phrasea\Cache\Cache + * @return Cache */ public function deleteMulti(array $keys); } diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php index 18925ea9f9..8e86565166 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php @@ -142,13 +142,4 @@ class Databox implements ControllerProviderInterface, ServiceProviderInterface { $this->getFirewall($app)->requireRightOnSbas($request->attributes->get('databox_id'), 'bas_modify_struct'); } - - /** - * @param Application $app - * @return Firewall - */ - private function getFirewall(Application $app) - { - return $app['firewall']; - } } diff --git a/lib/Alchemy/Phrasea/Core/Configuration/AccessRestriction.php b/lib/Alchemy/Phrasea/Core/Configuration/AccessRestriction.php index 39e8445b5d..ef76784639 100644 --- a/lib/Alchemy/Phrasea/Core/Configuration/AccessRestriction.php +++ b/lib/Alchemy/Phrasea/Core/Configuration/AccessRestriction.php @@ -14,6 +14,7 @@ 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 @@ -59,6 +60,25 @@ class AccessRestriction return in_array($databox->get_sbas_id(), $this->cache->fetch('available_databoxes'), true); } + /** + * @param \databox[] $databoxes + * @return \databox[] + */ + public function filterAvailableDataboxes(array $databoxes) + { + Assertion::allIsInstanceOf($databoxes, \databox::class); + + if (!$this->isRestricted()) { + return $databoxes; + } + + $available = array_flip($this->cache->fetch('available_databoxes')); + + return array_filter($databoxes, function (\databox $databox) use ($available) { + return isset($available[$databox->get_sbas_id()]); + }); + } + /** * Returns true if a collection is available given a configuration. * diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index 7904b1d56d..ca24737649 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -12,6 +12,9 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\Databox\CachedDataboxRepository; +use Alchemy\Phrasea\Databox\DataboxFactory; +use Alchemy\Phrasea\Databox\DbalDataboxRepository; use Silex\Application; use Silex\ServiceProviderInterface; @@ -121,6 +124,14 @@ class RepositoriesServiceProvider implements ServiceProviderInterface $app['repo.webhook-delivery'] = $app->share(function (PhraseaApplication $app) { return $app['orm.em']->getRepository('Phraseanet:WebhookEventDelivery'); }); + + $app['repo.databoxes'] = $app->share(function (PhraseaApplication $app) { + $factory = new DataboxFactory($app); + $appbox = $app->getApplicationBox(); + $repository = new DbalDataboxRepository($appbox->get_connection(), $factory); + + return new CachedDataboxRepository($repository, $app['cache'], $appbox->get_cache_key($appbox::CACHE_LIST_BASES), $factory); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Databox/CachedDataboxRepository.php b/lib/Alchemy/Phrasea/Databox/CachedDataboxRepository.php new file mode 100644 index 0000000000..13461d205c --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/CachedDataboxRepository.php @@ -0,0 +1,72 @@ +repository = $repository; + $this->cache = $cache; + $this->cacheKey = $cacheKey; + $this->factory = $factory; + } + + public function find($id) + { + $rows = $this->cache->fetch($this->cacheKey); + + if (isset($rows[$id])) { + return $this->factory->create($id, $rows[$id]); + } + + return $this->repository->find($id); + } + + public function findAll() + { + $rows = $this->cache->fetch($this->cacheKey); + + if (is_array($rows)) { + return $this->factory->createMany($rows); + } + + $databoxes = $this->repository->findAll(); + + $this->saveCache($databoxes); + + return $databoxes; + } + + /** + * @param \databox[] $databoxes + */ + private function saveCache(array $databoxes) + { + $rows = array(); + + foreach ($databoxes as $databox) { + $rows[$databox->get_sbas_id()] = $databox->getRawData(); + } + + $this->cache->save($this->cacheKey, $rows); + } +} diff --git a/lib/Alchemy/Phrasea/Databox/DataboxFactory.php b/lib/Alchemy/Phrasea/Databox/DataboxFactory.php new file mode 100644 index 0000000000..5c35af292f --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/DataboxFactory.php @@ -0,0 +1,51 @@ +app = $app; + } + + /** + * @param int $id + * @param array $raw + * @throws NotFoundHttpException when Databox could not be retrieved from Persistence layer + * @return \databox + */ + public function create($id, array $raw) + { + return new \databox($this->app, $id, $raw); + } + + /** + * @param array $rows + * @throws NotFoundHttpException when Databox could not be retrieved from Persistence layer + * @return \databox[] + */ + public function createMany(array $rows) + { + $databoxes = []; + + foreach ($rows as $id => $raw) { + $databoxes[$id] = new \databox($this->app, $id, $raw); + } + + return $databoxes; + } +} diff --git a/lib/Alchemy/Phrasea/Databox/DataboxRepositoryInterface.php b/lib/Alchemy/Phrasea/Databox/DataboxRepositoryInterface.php new file mode 100644 index 0000000000..9d39b4576a --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/DataboxRepositoryInterface.php @@ -0,0 +1,24 @@ +connection = $connection; + $this->factory = $factory; + } + + /** + * @param int $id + * @return \databox|null + */ + public function find($id) + { + $row = $this->fetchRow($id); + + if (is_array($row)) { + return $this->factory->create($id, $row); + } + + return null; + } + + /** + * @return \databox[] + */ + public function findAll() + { + return $this->factory->createMany($this->fetchRows()); + } + + /** + * @param int $id + * @return false|array + * @throws \Doctrine\DBAL\DBALException + */ + private function fetchRow($id) + { + $query = 'SELECT ord, viewname, label_en, label_fr, label_de, label_nl FROM sbas WHERE sbas_id = :id'; + $statement = $this->connection->prepare($query); + $statement->execute(['id' => $id]); + $row = $statement->fetch(\PDO::FETCH_ASSOC); + $statement->closeCursor(); + + return $row; + } + + /** + * @return array + * @throws \Doctrine\DBAL\DBALException + */ + private function fetchRows() + { + $query = 'SELECT sbas_id, ord, viewname, label_en, label_fr, label_de, label_nl FROM sbas'; + $statement = $this->connection->prepare($query); + $statement->execute(); + $rows = []; + while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) { + $id = $row['sbas_id']; + unset($row['sbas_id']); + $rows[$id] = $row; + } + $statement->closeCursor(); + + return $rows; + } +} diff --git a/lib/classes/appbox.php b/lib/classes/appbox.php index df0fa3138f..c1230b9864 100644 --- a/lib/classes/appbox.php +++ b/lib/classes/appbox.php @@ -10,6 +10,8 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Core\Configuration\AccessRestriction; +use Alchemy\Phrasea\Databox\DataboxRepositoryInterface; use Doctrine\ORM\Tools\SchemaTool; use MediaAlchemyst\Alchemyst; use MediaAlchemyst\Specification\Image as ImageSpecification; @@ -358,56 +360,14 @@ class appbox extends base */ public function get_databoxes() { - if ($this->databoxes) { - return $this->databoxes; + if (!$this->databoxes) { + $this->databoxes = $this->getAccessRestriction() + ->filterAvailableDataboxes($this->getDataboxRepository()->findAll()); } - $ret = []; - foreach ($this->retrieve_sbas_ids() as $sbas_id) { - try { - $databox = new \databox($this->app, $sbas_id); - if (!$this->app['conf.restrictions']->isDataboxAvailable($databox)) { - continue; - } - $ret[$sbas_id] = $databox; - } catch (NotFoundHttpException $e) { - $this->app['monolog']->error(sprintf('Databox %s is not reliable.', $sbas_id)); - } - } - - $this->databoxes = $ret; - return $this->databoxes; } - protected function retrieve_sbas_ids() - { - try { - $data = $this->get_data_from_cache(self::CACHE_SBAS_IDS); - if (is_array($data)) { - return $data; - } - } catch (\Exception $e) { - - } - $sql = 'SELECT sbas_id FROM sbas'; - - $ret = []; - - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute(); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - foreach ($rs as $row) { - $ret[] = (int) $row['sbas_id']; - } - - $this->set_data_to_cache($ret, self::CACHE_SBAS_IDS); - - return $ret; - } - public function get_databox($sbas_id) { $databoxes = $this->get_databoxes(); @@ -436,4 +396,20 @@ class appbox extends base parent::delete_data_from_cache($option); } + + /** + * @return AccessRestriction + */ + private function getAccessRestriction() + { + return $this->app['conf.restrictions']; + } + + /** + * @return DataboxRepositoryInterface + */ + private function getDataboxRepository() + { + return $this->app['repo.databoxes']; + } } diff --git a/lib/classes/base.php b/lib/classes/base.php index b7052cce39..fce6fa13fd 100644 --- a/lib/classes/base.php +++ b/lib/classes/base.php @@ -85,6 +85,9 @@ abstract class base implements cache_cacheableInterface return $this->connection; } + /** + * @return \Alchemy\Phrasea\Cache\Cache + */ public function get_cache() { return $this->app['cache']; @@ -118,7 +121,6 @@ abstract class base implements cache_cacheableInterface phrasea::reset_sbasDatas($appbox); phrasea::reset_baseDatas($appbox); phrasea::clear_sbas_params($this->app); - $keys[] = $this->get_cache_key(appbox::CACHE_SBAS_IDS); return $this->get_cache()->deleteMulti($keys); } @@ -133,6 +135,11 @@ abstract class base implements cache_cacheableInterface } } + /** + * @param mixed $option + * @throws Exception + * @return string + */ public function get_cache_key($option = null) { throw new Exception(__METHOD__ . ' must be defined in extended class'); diff --git a/lib/classes/cache/databox.php b/lib/classes/cache/databox.php index 4d19868ef4..d0f79a4823 100644 --- a/lib/classes/cache/databox.php +++ b/lib/classes/cache/databox.php @@ -102,7 +102,6 @@ class cache_databox break; case 'structure': $app->getApplicationBox()->delete_data_from_cache(\appbox::CACHE_LIST_BASES); - $app->getApplicationBox()->delete_data_from_cache(\appbox::CACHE_SBAS_IDS); $sql = 'DELETE FROM memcached WHERE site_id = :site_id AND type="structure" AND value = :value'; diff --git a/lib/classes/databox.php b/lib/classes/databox.php index 7ebb2d1768..2bd5ac9ce6 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -23,80 +23,32 @@ use Alchemy\Phrasea\Core\PhraseaTokens; class databox extends base { - /** - * - * @var int - */ + /** @var int */ protected $id; - - /** - * - * @var string - */ + /** @var string */ protected $structure; - - /** - * - * @var Array - */ + /** @var array */ protected static $_xpath_thesaurus = []; - - /** - * - * @var Array - */ + /** @var array */ protected static $_dom_thesaurus = []; - - /** - * - * @var Array - */ + /** @var array */ protected static $_thesaurus = []; - - /** - * - * @var Array - */ + /** @var array */ protected $_xpath_structure; - - /** - * - * @var DOMDocument - */ + /** @var DOMDocument */ protected $_dom_structure; - - /** - * - * @var DOMDocument - */ + /** @var DOMDocument */ protected $_dom_cterms; - - /** - * - * @var SimpleXMLElement - */ + /** @var SimpleXMLElement */ protected $_sxml_structure; - - /** - * - * @var databox_descriptionStructure - */ + /** @var databox_descriptionStructure */ protected $meta_struct; - - /** - * - * @var databox_subdefsStructure - */ + /** @var databox_subdefsStructure */ protected $subdef_struct; - - /** - * - * @var SimpleXMLElement - */ + /** @var SimpleXMLElement */ protected static $_sxml_thesaurus = []; const BASE_TYPE = self::DATA_BOX; - const CACHE_BASE_DATABOX = 'base_infos'; const CACHE_META_STRUCT = 'meta_struct'; const CACHE_THESAURUS = 'thesaurus'; const CACHE_COLLECTIONS = 'collections'; @@ -107,13 +59,13 @@ class databox extends base private $labels = []; private $ord; private $viewname; - private $loaded = false; /** * @param Application $app * @param int $sbas_id + * @param array $row */ - public function __construct(Application $app, $sbas_id) + public function __construct(Application $app, $sbas_id, array $row) { assert(is_int($sbas_id)); assert($sbas_id > 0); @@ -140,60 +92,24 @@ class databox extends base $this->user = $params['user']; $this->passwd = $params['password']; $this->dbname = $params['dbname']; - } - private function load() - { - if ($this->loaded) { - return; - } - - try { - $row = $this->get_data_from_cache(static::CACHE_BASE_DATABOX); - } catch (\Exception $e) { - $sql = 'SELECT ord, viewname, label_en, label_fr, label_de, label_nl - FROM sbas WHERE sbas_id = :sbas_id'; - $stmt = $this->app->getApplicationBox()->get_connection()->prepare($sql); - $stmt->execute(['sbas_id' => $this->id]); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $this->set_data_to_cache($row, static::CACHE_BASE_DATABOX); - } - - if (!$row) { - throw new NotFoundHttpException(sprintf('databox %d not found', $this->id)); - } - - $this->ord = $row['ord']; - $this->viewname = $row['viewname']; - $this->labels['fr'] = $row['label_fr']; - $this->labels['en'] = $row['label_en']; - $this->labels['de'] = $row['label_de']; - $this->labels['nl'] = $row['label_nl']; - - $this->loaded = true; + $this->loadFromRow($row); } public function get_viewname() { - $this->load(); - return $this->viewname ? : $this->dbname; } public function set_viewname($viewname) { - $this->load(); - $sql = 'UPDATE sbas SET viewname = :viewname WHERE sbas_id = :sbas_id'; - $stmt = $this->app->getApplicationBox()->get_connection()->prepare($sql); + $stmt = $this->get_appbox()->get_connection()->prepare($sql); $stmt->execute([':viewname' => $viewname, ':sbas_id' => $this->id]); $stmt->closeCursor(); - $this->delete_data_from_cache(static::CACHE_BASE_DATABOX); - $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); + $this->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); cache_databox::update($this->app, $this->id, 'structure'); $this->viewname = $viewname; @@ -203,8 +119,6 @@ class databox extends base public function get_ord() { - $this->load(); - return $this->ord; } @@ -213,7 +127,7 @@ class databox extends base */ public function get_appbox() { - return $this->app['phraseanet.appbox']; + return $this->app->getApplicationBox(); } /** @@ -264,7 +178,7 @@ class databox extends base } - $conn = $this->app->getApplicationBox()->get_connection(); + $conn = $this->get_appbox()->get_connection(); $sql = "SELECT b.server_coll_id FROM sbas s, bas b WHERE s.sbas_id = b.sbas_id AND b.sbas_id = :sbas_id @@ -299,8 +213,6 @@ class databox extends base public function get_label($code, $substitute = true) { - $this->load(); - if (!array_key_exists($code, $this->labels)) { throw new InvalidArgumentException(sprintf('Code %s is not defined', $code)); } @@ -314,22 +226,18 @@ class databox extends base public function set_label($code, $label) { - $this->load(); - if (!array_key_exists($code, $this->labels)) { throw new InvalidArgumentException(sprintf('Code %s is not defined', $code)); } $sql = "UPDATE sbas SET label_$code = :label WHERE sbas_id = :sbas_id"; - $stmt = $this->app->getApplicationBox()->get_connection()->prepare($sql); + $stmt = $this->get_appbox()->get_connection()->prepare($sql); $stmt->execute([':label' => $label, ':sbas_id' => $this->id]); $stmt->closeCursor(); $this->labels[$code] = $label; - $this->delete_data_from_cache(static::CACHE_BASE_DATABOX); - phrasea::reset_sbasDatas($this->app['phraseanet.appbox']); return $this; @@ -533,17 +441,16 @@ class databox extends base $stmt->closeCursor(); $sql = "DELETE FROM sbas WHERE sbas_id = :sbas_id"; - $stmt = $this->app->getApplicationBox()->get_connection()->prepare($sql); + $stmt = $this->get_appbox()->get_connection()->prepare($sql); $stmt->execute([':sbas_id' => $this->id]); $stmt->closeCursor(); $sql = "DELETE FROM sbasusr WHERE sbas_id = :sbas_id"; - $stmt = $this->app->getApplicationBox()->get_connection()->prepare($sql); + $stmt = $this->get_appbox()->get_connection()->prepare($sql); $stmt->execute([':sbas_id' => $this->id]); $stmt->closeCursor(); - $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); - $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_SBAS_IDS); + $this->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); return; } @@ -694,7 +601,6 @@ class databox extends base $databox = $app->findDataboxById($sbas_id); $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - $app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_SBAS_IDS); phrasea::reset_sbasDatas($app['phraseanet.appbox']); @@ -798,7 +704,7 @@ class databox extends base $stmt->execute(); $stmt->closeCursor(); - $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); + $this->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); return; } @@ -845,7 +751,7 @@ class databox extends base public function get_mountable_colls() { /** @var Connection $conn */ - $conn = $this->app->getApplicationBox()->get_connection(); + $conn = $this->get_appbox()->get_connection(); $colls = []; $sql = 'SELECT server_coll_id FROM bas WHERE sbas_id = :sbas_id'; @@ -888,7 +794,7 @@ class databox extends base public function get_activable_colls() { /** @var Connection $conn */ - $conn = $this->app->getApplicationBox()->get_connection(); + $conn = $this->get_appbox()->get_connection(); $base_ids = []; $sql = 'SELECT base_id FROM bas WHERE sbas_id = :sbas_id AND active = "0"'; @@ -932,7 +838,7 @@ class databox extends base $this->meta_struct = null; - $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); + $this->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); $this->delete_data_from_cache(self::CACHE_STRUCTURE); $this->delete_data_from_cache(self::CACHE_META_STRUCT); @@ -1062,7 +968,7 @@ class databox extends base */ public function registerAdmin(User $user) { - $conn = $this->app->getApplicationBox()->get_connection(); + $conn = $this->get_appbox()->get_connection(); $this->app->getAclForUser($user) ->give_access_to_sbas([$this->id]) @@ -1575,4 +1481,34 @@ class databox extends base return false; } + + /** + * @param array $row + */ + private function loadFromRow(array $row) + { + $this->ord = $row['ord']; + $this->viewname = $row['viewname']; + $this->labels['fr'] = $row['label_fr']; + $this->labels['en'] = $row['label_en']; + $this->labels['de'] = $row['label_de']; + $this->labels['nl'] = $row['label_nl']; + } + + /** + * Return an array that can be used to restore databox. + * + * @return array + */ + public function getRawData() + { + return [ + 'ord' => $this->ord, + 'viewname' => $this->viewname, + 'label_en' => $this->labels['en'], + 'label_fr' => $this->labels['fr'], + 'label_de' => $this->labels['de'], + 'label_nl' => $this->labels['nl'], + ]; + } } diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php index 715d0cd6e9..a074ec40b9 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php @@ -111,7 +111,8 @@ class DataboxTest extends \PhraseanetAuthenticatedWebTestCase $this->setAdmin(true); - $collection = \collection::create(self::$DI['app'], $databox, self::$DI['app']['phraseanet.appbox'], 'TESTTODELETE'); + $app = $this->getApplication(); + $collection = \collection::create($app, $databox, $app['phraseanet.appbox'], 'TESTTODELETE'); $this->XMLHTTPRequest('POST', '/admin/databox/' . $databox->get_sbas_id() . '/collections/order/', [ 'order' => [ @@ -394,7 +395,8 @@ class DataboxTest extends \PhraseanetAuthenticatedWebTestCase $this->assertTrue(is_object($content)); $this->assertObjectHasAttribute('sbas_id', $content, $response->getContent()); - $this->assertTrue(!!self::$DI['app']->getApplicationBox()->is_databox_indexable(new \databox(self::$DI['app'], self::$DI['collection']->get_sbas_id()))); + $app = $this->getApplication(); + $this->assertTrue(!!$app->getApplicationBox()->is_databox_indexable($app->findDataboxById(self::$DI['collection']->get_sbas_id()))); } /** diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/SubdefsTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/SubdefsTest.php index 0e5ff69a56..7c8c1572e5 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/SubdefsTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/SubdefsTest.php @@ -14,13 +14,15 @@ class SubdefsTest extends \PhraseanetAuthenticatedWebTestCase { protected $client; - protected $databox; + protected $databox_id; public function setUp() { parent::setUp(); - $databoxes = self::$DI['app']->getDataboxes(); - $this->databox = array_shift($databoxes); + $databoxes = $this->getApplication()->getDataboxes(); + // Can not keep databox instance as appbox is cleared + $databox = array_shift($databoxes); + $this->databox_id = $databox->get_sbas_id(); } public function getSubdefName() @@ -33,30 +35,31 @@ class SubdefsTest extends \PhraseanetAuthenticatedWebTestCase */ public function testRouteGetSubdef() { - self::$DI['client']->request("GET", "/admin/subdefs/" . $this->databox->get_sbas_id() . "/"); + self::$DI['client']->request("GET", "/admin/subdefs/" . $this->databox_id . "/"); $this->assertTrue(self::$DI['client']->getResponse()->isOk()); } public function testPostRouteAddSubdef() { $name = $this->getSubdefName(); - self::$DI['client']->request("POST", "/admin/subdefs/" . $this->databox->get_sbas_id() . "/", ['add_subdef' => [ + self::$DI['client']->request("POST", "/admin/subdefs/" . $this->databox_id . "/", ['add_subdef' => [ 'class' => 'thumbnail', 'name' => $name, 'group' => 'image' ]]); $this->assertTrue(self::$DI['client']->getResponse()->isRedirect()); - $subdefs = new \databox_subdefsStructure(new \databox(self::$DI['app'], $this->databox->get_sbas_id()), self::$DI['app']['translator']); + $app = $this->getApplication(); + $subdefs = new \databox_subdefsStructure($app->findDataboxById($this->databox_id), $app['translator']); $subdefs->delete_subdef('image', $name); } public function testPostRouteDeleteSubdef() { - $subdefs = $this->databox->get_subdef_structure(); + $subdefs = $this->getApplication()->findDataboxById($this->databox_id)->get_subdef_structure(); $name = $this->getSubdefName(); $subdefs->add_subdef("image", $name, "thumbnail"); - self::$DI['client']->request("POST", "/admin/subdefs/" . $this->databox->get_sbas_id() . "/", ['delete_subdef' => 'image_' . $name]); + self::$DI['client']->request("POST", "/admin/subdefs/" . $this->databox_id . "/", ['delete_subdef' => 'image_' . $name]); $this->assertTrue(self::$DI['client']->getResponse()->isRedirect()); try { $subdefs->get_subdef("image", $name); @@ -68,10 +71,10 @@ class SubdefsTest extends \PhraseanetAuthenticatedWebTestCase public function testPostRouteAddSubdefWithNoParams() { - $subdefs = $this->databox->get_subdef_structure(); + $subdefs = $this->getApplication()->findDataboxById($this->databox_id)->get_subdef_structure(); $name = $this->getSubdefName(); $subdefs->add_subdef("image", $name, "thumbnail"); - self::$DI['client']->request("POST", "/admin/subdefs/" . $this->databox->get_sbas_id() . "/" + self::$DI['client']->request("POST", "/admin/subdefs/" . $this->databox_id . "/" , ['subdefs' => [ 'image_' . $name ] @@ -87,7 +90,8 @@ class SubdefsTest extends \PhraseanetAuthenticatedWebTestCase ); $this->assertTrue(self::$DI['client']->getResponse()->isRedirect()); - $subdefs = new \databox_subdefsStructure(new \databox(self::$DI['app'], $this->databox->get_sbas_id()), self::$DI['app']['translator']); + $app = $this->getApplication(); + $subdefs = new \databox_subdefsStructure($app->findDataboxById($this->databox_id), $app['translator']); $subdef = $subdefs->get_subdef("image", $name); /* @var $subdef \databox_subdef */ diff --git a/tests/Alchemy/Tests/Phrasea/Databox/CachedDataboxRepositoryTest.php b/tests/Alchemy/Tests/Phrasea/Databox/CachedDataboxRepositoryTest.php new file mode 100644 index 0000000000..4810c4883a --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Databox/CachedDataboxRepositoryTest.php @@ -0,0 +1,117 @@ +cache = $this->prophesize(Cache::class); + $this->repository = $this->prophesize(DataboxRepositoryInterface::class); + $this->factory = $this->prophesize(DataboxFactory::class); + + $this->sut = new CachedDataboxRepository( + $this->repository->reveal(), + $this->cache->reveal(), + $this->cacheKey, + $this->factory->reveal() + ); + } + + public function testItImplementsDataboxRepositoryInterface() + { + $this->assertInstanceOf(DataboxRepositoryInterface::class, $this->sut); + } + + public function testItFindsASpecificDataboxWhenNotInCache() + { + $databox = $this->prophesize(\databox::class); + + $this->cache->fetch($this->cacheKey) + ->willReturn(false); + $this->repository->find(42) + ->willReturn($databox->reveal()); + + $this->assertSame($databox->reveal(), $this->sut->find(42)); + } + + public function testItHydrateDataboxWhenInCache() + { + $databox = $this->prophesize(\databox::class); + + $this->cache->fetch($this->cacheKey) + ->willReturn([42 => ['foo' => 'bar']]); + $this->repository->find(42) + ->shouldNotBeCalled(); + $this->factory->create(42, ['foo' => 'bar']) + ->willReturn($databox->reveal()); + + $this->assertSame($databox->reveal(), $this->sut->find(42)); + } + + public function testItProperlySaveCacheOnFindAll() + { + $databox = $this->prophesize(\databox::class); + $databox->get_sbas_id() + ->willReturn(42); + $databox->getRawData() + ->willReturn(['foo' => 'bar']); + + $cache_data = [42 => ['foo' => 'bar']]; + $databoxes = [42 => $databox->reveal()]; + + $this->cache->fetch($this->cacheKey) + ->willReturn(false); + $this->repository->findAll() + ->willReturn($databoxes); + $this->cache->save($this->cacheKey, $cache_data) + ->shouldBeCalled(); + + $this->factory->createMany(Argument::any()) + ->shouldNotBeCalled(); + + $this->assertSame($databoxes, $this->sut->findAll()); + } + + public function testItFindsAllDeclaredDataboxesFromCache() + { + $databox = $this->prophesize(\databox::class); + + $cache_data = [42 => ['foo' => 'bar']]; + $databoxes = [42 => $databox->reveal()]; + + $this->cache->fetch($this->cacheKey) + ->willReturn($cache_data); + $this->repository->findAll() + ->shouldNotBeCalled(); + $this->factory->createMany($cache_data) + ->willReturn($databoxes); + + $this->assertSame($databoxes, $this->sut->findAll()); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Databox/DbalDataboxRepositoryTest.php b/tests/Alchemy/Tests/Phrasea/Databox/DbalDataboxRepositoryTest.php new file mode 100644 index 0000000000..e0465b99f4 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Databox/DbalDataboxRepositoryTest.php @@ -0,0 +1,102 @@ +connection = $this->prophesize(Connection::class); + $this->factory = $this->prophesize(DataboxFactory::class); + + $this->sut = new DbalDataboxRepository($this->connection->reveal(), $this->factory->reveal()); + } + + public function testItImplementsDataboxRepositoryInterface() + { + $this->assertInstanceOf(DataboxRepositoryInterface::class, $this->sut); + } + + public function testItFindsDataboxProperly() + { + $databox = $this->prophesize(\databox::class); + + $statement = $this->prophesize(Statement::class); + $this->connection + ->prepare('SELECT ord, viewname, label_en, label_fr, label_de, label_nl FROM sbas WHERE sbas_id = :id') + ->willReturn($statement->reveal()); + $statement->execute(['id' => 42]) + ->shouldBeCalled(); + $statement->fetch(\PDO::FETCH_ASSOC) + ->willReturn(['foo' => 'bar']); + $statement->closeCursor() + ->shouldBeCalled(); + + $this->factory->create(42, ['foo' => 'bar']) + ->willReturn($databox->reveal()); + + $this->assertSame($databox->reveal(), $this->sut->find(42)); + } + + public function testItReturnsNullOnNonExistentDatabox() + { + $statement = $this->prophesize(Statement::class); + $this->connection + ->prepare('SELECT ord, viewname, label_en, label_fr, label_de, label_nl FROM sbas WHERE sbas_id = :id') + ->willReturn($statement->reveal()); + $statement->execute(['id' => 42]) + ->shouldBeCalled(); + $statement->fetch(\PDO::FETCH_ASSOC) + ->willReturn(false); + $statement->closeCursor() + ->shouldBeCalled(); + + $this->factory->create(42, Argument::any()) + ->shouldNotBeCalled(); + + $this->assertNull($this->sut->find(42)); + } + + public function testItFindsAllDataboxes() + { + $databox = $this->prophesize(\databox::class); + + $statement = $this->prophesize(Statement::class); + $this->connection + ->prepare('SELECT sbas_id, ord, viewname, label_en, label_fr, label_de, label_nl FROM sbas') + ->willReturn($statement->reveal()); + $statement->execute() + ->shouldBeCalled(); + $statement->fetch(\PDO::FETCH_ASSOC) + ->willReturn(['sbas_id' => 42, 'foo' => 'bar'], false); + $statement->closeCursor() + ->shouldBeCalled(); + + $this->factory->createMany([42 => ['foo' => 'bar']]) + ->willReturn([$databox->reveal()]); + + $this->assertSame([$databox->reveal()], $this->sut->findAll()); + } +}