From ea6a4fdbf0a43000ae8e4db572283cdddabb09ce Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Wed, 8 Jul 2015 19:54:06 +0200 Subject: [PATCH 01/17] Extract repository and factory classes for collections --- .../Collection/CachedCollectionRepository.php | 87 +++ .../Phrasea/Collection/CollectionFactory.php | 55 ++ .../Collection/CollectionReference.php | 144 +++++ .../CollectionReferenceRepository.php | 30 + .../Collection/CollectionRepository.php | 26 + .../DbalCollectionReferenceRepository.php | 110 ++++ .../Collection/DbalCollectionRepository.php | 107 ++++ lib/Alchemy/Phrasea/Command/RecordAdd.php | 2 +- .../Phrasea/Command/Upgrade/Step31.php | 2 +- .../Controller/Admin/CollectionController.php | 36 +- .../Controller/Admin/DataboxController.php | 2 +- .../Controller/Admin/FeedController.php | 4 +- .../Controller/Admin/UserController.php | 6 +- .../Phrasea/Controller/Api/V1Controller.php | 8 +- .../Controller/PermalinkController.php | 2 +- .../Prod/MoveCollectionController.php | 2 +- .../Controller/Prod/StoryController.php | 2 +- .../Controller/Prod/UploadController.php | 2 +- .../Controller/Root/AccountController.php | 2 +- .../Controller/Root/LoginController.php | 2 +- .../Provider/BorderManagerServiceProvider.php | 2 +- .../Provider/RepositoriesServiceProvider.php | 22 + .../Databox/DataboxConnectionProvider.php | 23 + lib/Alchemy/Phrasea/Helper/User/Edit.php | 6 +- lib/Alchemy/Phrasea/Model/Entities/Feed.php | 2 +- .../Phrasea/Model/Entities/LazaretFile.php | 2 +- .../Phrasea/Model/Entities/Registration.php | 2 +- lib/Alchemy/Phrasea/Out/Module/PDF.php | 2 +- .../SearchEngine/SearchEngineOptions.php | 4 +- .../Phrasea/TaskManager/Job/ArchiveJob.php | 4 +- .../TaskManager/Job/EmptyCollectionJob.php | 2 +- .../TaskManager/Job/RecordMoverJob.php | 2 +- lib/classes/ACL.php | 4 +- lib/classes/appbox.php | 7 +- lib/classes/collection.php | 592 +++++++++--------- lib/classes/databox.php | 64 +- lib/classes/patch/370alpha7a.php | 2 +- lib/classes/patch/390alpha13a.php | 2 +- lib/classes/record/adapter.php | 2 +- .../Controller/Admin/AdminCollectionTest.php | 12 +- tests/classes/ACLTest.php | 2 +- tests/classes/PhraseanetTestCase.php | 6 +- tests/classes/collectionTest.php | 2 +- 43 files changed, 971 insertions(+), 428 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionFactory.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionReference.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionReferenceRepository.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionRepository.php create mode 100644 lib/Alchemy/Phrasea/Collection/DbalCollectionReferenceRepository.php create mode 100644 lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php create mode 100644 lib/Alchemy/Phrasea/Databox/DataboxConnectionProvider.php diff --git a/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php new file mode 100644 index 0000000000..fd918a53cd --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php @@ -0,0 +1,87 @@ +repository = $repository; + $this->cache = $cache; + $this->cacheKey = $cacheKey; + } + + /** + * @param int $databoxId + * @return \collection[] + */ + public function findAllByDatabox($databoxId) + { + $cacheKey = hash('sha256', $this->cacheKey . '.findAll.' . $databoxId); + $collections = $this->cache->fetch($cacheKey); + + if ($collections === false) { + $collections = $this->repository->findAllByDatabox($databoxId); + $this->save($cacheKey, $collections); + } + + return $collections; + } + + /** + * @param int $baseId + * @return \collection|null + */ + public function find($baseId) + { + $cacheKey = hash('sha256', $this->cacheKey . '.find.' . $baseId); + $collection = $this->cache->fetch($cacheKey); + + if ($collection === false) { + $collection = $this->repository->find($baseId); + $this->save($cacheKey, $collection); + } + + return $collection; + } + + /** + * @param int $databoxId + * @param int $collectionId + * @return \collection|null + */ + public function findByCollectionId($databoxId, $collectionId) + { + $cacheKey = hash('sha256', $this->cacheKey . '.findByCollection.' . $databoxId . $collectionId); + $collection = $this->cache->fetch($cacheKey); + + if ($collection === false) { + $collection = $this->repository->findByCollectionId($databoxId, $collectionId); + $this->save($cacheKey, $collection); + } + + return $collection; + } + + private function save($key, $value) + { + $this->cache->save($key, $value); + } +} diff --git a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php new file mode 100644 index 0000000000..bd3963fc76 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php @@ -0,0 +1,55 @@ +app = $application; + } + + /** + * @param CollectionReference $reference + * @param array $row + * @return \collection + */ + public function create(CollectionReference $reference, array $row) + { + return new \collection($this->app, $reference->getBaseId(), $reference, $row); + } + + /** + * @param CollectionReference[] $collectionReferences + * @param array $rows + * @return array + */ + public function createMany($collectionReferences, array $rows) + { + Assertion::allIsInstanceOf($collectionReferences, CollectionReference::class); + + $collections = []; + $indexedReferences = []; + + foreach ($collectionReferences as $reference) { + $indexedReferences[$reference->getCollectionId()] = $reference; + } + + foreach ($rows as $row) { + $collections[$row['coll_id']] = $this->create($indexedReferences[$row['coll_id']], $row); + } + + return $collections; + } +} diff --git a/lib/Alchemy/Phrasea/Collection/CollectionReference.php b/lib/Alchemy/Phrasea/Collection/CollectionReference.php new file mode 100644 index 0000000000..c5f51af7d4 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/CollectionReference.php @@ -0,0 +1,144 @@ +baseId = (int) $baseId; + $this->databoxId = (int) $databoxId; + $this->collectionId = (int) $collectionId; + $this->displayIndex = (int) $displayIndex; + $this->isActive = (bool) $isActive; + $this->alias = (string) $alias; + } + + /** + * @return int + */ + public function getDataboxId() + { + return $this->databoxId; + } + + /** + * @return int + */ + public function getBaseId() + { + return $this->baseId; + } + + /** + * @return int + */ + public function getCollectionId() + { + return $this->collectionId; + } + + /** + * @return int + */ + public function getDisplayIndex() + { + return $this->displayIndex; + } + + /** + * @param int $index + * @return $this + */ + public function setDisplayIndex($index) + { + $this->displayIndex = (int) $index; + + return $this; + } + + /** + * @return boolean + */ + public function isActive() + { + return $this->isActive; + } + + /** + * @return $this + */ + public function disable() + { + $this->isActive = false; + + return $this; + } + + /** + * @return $this + */ + public function enable() + { + $this->isActive = true; + + return $this; + } + + /** + * @return string + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @param string $alias + * @return $this + */ + public function setAlias($alias) + { + $this->alias = (string) $alias; + + return $this; + } +} diff --git a/lib/Alchemy/Phrasea/Collection/CollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/CollectionReferenceRepository.php new file mode 100644 index 0000000000..0d4f92f037 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/CollectionReferenceRepository.php @@ -0,0 +1,30 @@ +connection = $connection; + } + + /** + * @return CollectionReference[] + */ + public function findAll() + { + return $this->createManyReferences($this->connection->fetchAll(self::$query)); + } + + /** + * @param int $databoxId + * @return CollectionReference[] + */ + public function findAllByDatabox($databoxId) + { + $query = self::$query . ' WHERE sbas_id = :databoxId'; + $rows = $this->connection->fetchAll($query, [ ':databoxId' => $databoxId ]); + + return $this->createManyReferences($rows); + } + + /** + * @param int $baseId + * @return CollectionReference|null + */ + public function find($baseId) + { + $query = self::$query . ' WHERE base_id = :baseId'; + $row = $this->connection->fetchAssoc($query, [ ':baseId' => $baseId ]); + + if ($row !== false) { + return $this->createReference($row); + } + + return null; + } + + /** + * @param int $databoxId + * @param int $collectionId + * @return CollectionReference|null + */ + public function findByCollectionId($databoxId, $collectionId) + { + $query = self::$query . ' WHERE sbas_id = :databoxId AND server_coll_id = :collectionId'; + $row = $this->connection->fetchAssoc($query, [ ':databoxId' => $databoxId, ':collectionId' => $collectionId ]); + + if ($row !== false) { + return $this->createReference($row); + } + + return null; + } + + /** + * @param array $row + * @return CollectionReference + */ + private function createReference(array $row) + { + return new CollectionReference( + $row['baseId'], + $row['databoxId'], + $row['collectionId'], + $row['displayIndex'], + $row['isActive'], + $row['alias'] + ); + } + + /** + * @param $rows + * @return array + */ + private function createManyReferences($rows) + { + $references = []; + + foreach ($rows as $row) { + $references[$row['baseId']] = $this->createReference($row); + } + + return $references; + } +} diff --git a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php new file mode 100644 index 0000000000..826894dcd3 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php @@ -0,0 +1,107 @@ +connectionProvider = $connectionProvider; + $this->referenceRepository = $referenceRepository; + $this->collectionFactory = $collectionFactory; + } + + /** + * @param int $databoxId + * @return \collection[] + */ + public function findAllByDatabox($databoxId) + { + $references = $this->referenceRepository->findAllByDatabox($databoxId); + $connection = $this->connectionProvider->getConnection($databoxId); + + $params = []; + + foreach ($references as $reference) { + $params[':id_' . $reference->getCollectionId()] = $reference->getCollectionId(); + } + + $query = self::$query . sprintf(' WHERE coll_id IN (%s)', implode(', ', array_keys($params))); + $rows = $connection->fetchAll($query, $params); + + return $this->collectionFactory->createMany($references, $rows); + } + + /** + * @param int $baseId + * @return \collection|null + */ + public function find($baseId) + { + $reference = $this->referenceRepository->find($baseId); + + if ($reference === null) { + return null; + } + + $connection = $this->connectionProvider->getConnection($reference->getDataboxId()); + + $query = self::$query . ' WHERE coll_id = :collectionId'; + $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); + + if ($row !== false) { + return $this->collectionFactory->create($reference, $row); + } + + return null; + } + + /** + * @param int $databoxId + * @param int $collectionId + * @return \collection|null + */ + public function findByCollectionId($databoxId, $collectionId) + { + $reference = $this->referenceRepository->findByCollectionId($databoxId, $collectionId); + + if ($reference === null) { + return null; + } + + $connection = $this->connectionProvider->getConnection($databoxId); + + $query = self::$query . ' WHERE coll_id = :collectionId'; + $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); + + if ($row !== false) { + return $this->collectionFactory->create($row['baseId'], $reference, $row); + } + + return null; + } +} diff --git a/lib/Alchemy/Phrasea/Command/RecordAdd.php b/lib/Alchemy/Phrasea/Command/RecordAdd.php index 11369e3126..fd4c05c857 100644 --- a/lib/Alchemy/Phrasea/Command/RecordAdd.php +++ b/lib/Alchemy/Phrasea/Command/RecordAdd.php @@ -43,7 +43,7 @@ class RecordAdd extends Command protected function doExecute(InputInterface $input, OutputInterface $output) { try { - $collection = \collection::get_from_base_id($this->container, $input->getArgument('base_id')); + $collection = \collection::getByBaseId($this->container, $input->getArgument('base_id')); } catch (\Exception $e) { throw new \InvalidArgumentException(sprintf('Collection %s is invalid', $input->getArgument('base_id'))); } diff --git a/lib/Alchemy/Phrasea/Command/Upgrade/Step31.php b/lib/Alchemy/Phrasea/Command/Upgrade/Step31.php index b90f181a08..f2944e783e 100644 --- a/lib/Alchemy/Phrasea/Command/Upgrade/Step31.php +++ b/lib/Alchemy/Phrasea/Command/Upgrade/Step31.php @@ -125,7 +125,7 @@ class Step31 implements DatasUpgraderInterface $uuid = Uuid::uuid4(); try { $media = $this->app->getMediaFromUri($pathfile); - $collection = \collection::get_from_coll_id($this->$app, $databox, (int) $record['coll_id']); + $collection = \collection::getByCollectionId($this->$app, $databox, (int) $record['coll_id']); $file = new File($this->app, $media, $collection); $uuid = $file->getUUID(true, true); diff --git a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php index 59aa532f05..b1c55ac100 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php @@ -33,7 +33,7 @@ class CollectionController extends Controller */ public function getCollection(Request $request, $bas_id) { - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); $admins = []; @@ -144,7 +144,7 @@ class CollectionController extends Controller $success = false; $msg = $this->app->trans('An error occurred'); - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { if ($collection->get_record_amount() <= 500) { $collection->empty_collection(500); @@ -184,7 +184,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $this->app->getApplicationBox()->write_collection_pic( @@ -224,7 +224,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $this->app->getApplicationBox()->write_collection_pic( @@ -264,7 +264,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $collection->update_logo(null); @@ -323,7 +323,7 @@ class CollectionController extends Controller ]); } - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $this->app->getApplicationBox()->write_collection_pic( @@ -378,7 +378,7 @@ class CollectionController extends Controller ]); } - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $this->app->getApplicationBox()->write_collection_pic( @@ -432,7 +432,7 @@ class CollectionController extends Controller ]); } - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $this->app->getApplicationBox()->write_collection_pic( @@ -468,7 +468,7 @@ class CollectionController extends Controller $success = false; $msg = $this->app->trans('An error occured'); - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { if ($collection->get_record_amount() > 0) { @@ -522,7 +522,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $collection->unmount_collection($this->app); @@ -562,7 +562,7 @@ class CollectionController extends Controller $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $collection->set_name($name); @@ -594,7 +594,7 @@ class CollectionController extends Controller $this->app->abort(400, $this->app->trans('Invalid labels parameter')); } - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); $success = true; try { @@ -638,7 +638,7 @@ class CollectionController extends Controller $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $collection->set_public_presentation($watermark); @@ -671,7 +671,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $collection->enable($this->app->getApplicationBox()); @@ -704,7 +704,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); try { $collection->disable($this->app->getApplicationBox()); @@ -736,7 +736,7 @@ class CollectionController extends Controller { /** @var \databox $databox */ $databox = $this->app->findDataboxById(\phrasea::sbasFromBas($this->app, $bas_id)); - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); $structFields = $suggestedValues = $basePrefs = []; /** @var \databox_field $meta */ @@ -806,7 +806,7 @@ class CollectionController extends Controller { $success = false; - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); $prefs = $request->request->get('str'); try { @@ -843,7 +843,7 @@ class CollectionController extends Controller */ public function getDetails($bas_id) { - $collection = \collection::get_from_base_id($this->app, $bas_id); + $collection = \collection::getByBaseId($this->app, $bas_id); $out = ['total' => ['totobj' => 0, 'totsiz' => 0, 'mega' => '0', 'giga' => '0'], 'result' => []]; diff --git a/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php b/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php index d1f6e8789b..21dd1a9bf0 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php @@ -639,7 +639,7 @@ class DataboxController extends Controller { try { foreach ($request->request->get('order', []) as $data) { - $collection = \collection::get_from_base_id($this->app, $data['id']); + $collection = \collection::getByBaseId($this->app, $data['id']); $collection->set_ord($data['offset']); } $success = true; diff --git a/lib/Alchemy/Phrasea/Controller/Admin/FeedController.php b/lib/Alchemy/Phrasea/Controller/Admin/FeedController.php index 33becac80e..95752a53a3 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/FeedController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/FeedController.php @@ -56,7 +56,7 @@ class FeedController extends Controller if ($request->request->get('public') == '1') { $feed->setIsPublic(true); } elseif ($request->request->get('base_id')) { - $feed->setCollection(\collection::get_from_base_id($this->app, $request->request->get('base_id'))); + $feed->setCollection(\collection::getByBaseId($this->app, $request->request->get('base_id'))); } $publisher->setFeed($feed); @@ -106,7 +106,7 @@ class FeedController extends Controller } try { - $collection = \collection::get_from_base_id($this->app, $request->request->get('base_id')); + $collection = \collection::getByBaseId($this->app, $request->request->get('base_id')); } catch (\Exception $e) { $collection = null; } diff --git a/lib/Alchemy/Phrasea/Controller/Admin/UserController.php b/lib/Alchemy/Phrasea/Controller/Admin/UserController.php index 6c34c876a9..501b385f57 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/UserController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/UserController.php @@ -454,7 +454,7 @@ class UserController extends Controller $registrationRepository->getUserRegistrations( $user, array_map(function ($baseId) { - return \collection::get_from_base_id($this->app, $baseId); + return \collection::getByBaseId($this->app, $baseId); }, $bases) ) as $registration) { $registrationManipulator->rejectRegistration($registration); @@ -472,7 +472,7 @@ class UserController extends Controller foreach ($registrationRepository->getUserRegistrations( $user, array_map(function ($baseId) { - return \collection::get_from_base_id($this->app, $baseId); + return \collection::getByBaseId($this->app, $baseId); }, $bases) ) as $registration) { $done[$usr][$registration->getBaseId()] = true; @@ -494,7 +494,7 @@ class UserController extends Controller $acceptColl = $denyColl = []; foreach ($bases as $bas => $isok) { - $collection = \collection::get_from_base_id($this->app, $bas); + $collection = \collection::getByBaseId($this->app, $bas); if ($isok) { $acceptColl[] = $collection->get_label($this->app['locale']); diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php index a283220cd2..7229b5832a 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php @@ -798,7 +798,7 @@ class V1Controller extends Controller return $this->getBadRequestAction($request, 'Missing base_id parameter'); } - $collection = \collection::get_from_base_id($this->app, $request->get('base_id')); + $collection = \collection::getByBaseId($this->app, $request->get('base_id')); if (!$this->getAclForUser()->has_right_on_base($request->get('base_id'), 'canaddrecord')) { return Result::createError($request, 403, sprintf( @@ -896,7 +896,7 @@ class V1Controller extends Controller $media = $this->app->getMediaFromUri($file->getPathname()); $record = $this->findDataboxById($request->get('databox_id'))->get_record($request->get('record_id')); $base_id = $record->get_base_id(); - $collection = \collection::get_from_base_id($this->app, $base_id); + $collection = \collection::getByBaseId($this->app, $base_id); if (!$this->getAclForUser()->has_right_on_base($base_id, 'canaddrecord')) { return Result::create($request, 403, sprintf( 'You do not have access to collection %s', $collection->get_label($this->app['locale.I18n']) @@ -1572,7 +1572,7 @@ class V1Controller extends Controller $record = $databox->get_record($record_id); try { - $collection = \collection::get_from_base_id($this->app, $request->get('base_id')); + $collection = \collection::getByBaseId($this->app, $request->get('base_id')); $record->move_to_collection($collection, $this->getApplicationBox()); return Result::create($request, ["record" => $this->listRecord($request, $record)])->createResponse(); @@ -2064,7 +2064,7 @@ class V1Controller extends Controller $this->app->abort(400, 'Request body does not contains a valid "story" object'); } - $collection = \collection::get_from_base_id($this->app, $data->{'base_id'}); + $collection = \collection::getByBaseId($this->app, $data->{'base_id'}); if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { $this->app->abort(403, sprintf('You can not create a story on this collection %s', $collection->get_base_id())); diff --git a/lib/Alchemy/Phrasea/Controller/PermalinkController.php b/lib/Alchemy/Phrasea/Controller/PermalinkController.php index e5f4a94e8b..4b33e4ab91 100644 --- a/lib/Alchemy/Phrasea/Controller/PermalinkController.php +++ b/lib/Alchemy/Phrasea/Controller/PermalinkController.php @@ -157,7 +157,7 @@ class PermalinkController extends AbstractDelivery return $this->deliverContentWithCaptionLink($request, $record, $subdef, $watermark, $stamp, $token); } - $collection = \collection::get_from_base_id($this->app, $record->get_base_id()); + $collection = \collection::getByBaseId($this->app, $record->get_base_id()); switch ($collection->get_pub_wm()) { default: case 'none': diff --git a/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php b/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php index fee6e9d70e..b45aafa6d6 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php @@ -58,7 +58,7 @@ class MoveCollectionController extends Controller } try { - $collection = \collection::get_from_base_id($this->app, $request->request->get('base_id')); + $collection = \collection::getByBaseId($this->app, $request->request->get('base_id')); } catch (\Exception_Databox_CollectionNotFound $e) { $datas['message'] = $this->app->trans('Invalid target collection'); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php b/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php index bd1cceadc4..1d335b7312 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/StoryController.php @@ -33,7 +33,7 @@ class StoryController extends Controller public function postCreateFormAction(Request $request) { - $collection = \collection::get_from_base_id($this->app, $request->request->get('base_id')); + $collection = \collection::getByBaseId($this->app, $request->request->get('base_id')); if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { throw new AccessDeniedHttpException('You can not create a story on this collection'); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php b/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php index 479fab824b..feddfd1095 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/UploadController.php @@ -133,7 +133,7 @@ class UploadController extends Controller $this->getFilesystem()->rename($uploadedFilename, $renamedFilename); $media = $this->app->getMediaFromUri($renamedFilename); - $collection = \collection::get_from_base_id($this->app, $base_id); + $collection = \collection::getByBaseId($this->app, $base_id); $lazaretSession = new LazaretSession(); $lazaretSession->setUser($this->getAuthenticatedUser()); diff --git a/lib/Alchemy/Phrasea/Controller/Root/AccountController.php b/lib/Alchemy/Phrasea/Controller/Root/AccountController.php index eba11c0376..0edafb2690 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/AccountController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/AccountController.php @@ -312,7 +312,7 @@ class AccountController extends Controller if (0 !== count($registrations)) { foreach ($registrations as $baseId) { $this->getRegistrationManipulator() - ->createRegistration($user, \collection::get_from_base_id($this->app, $baseId)); + ->createRegistration($user, \collection::getByBaseId($this->app, $baseId)); } $this->app->addFlash('success', $this->app->trans('Your registration requests have been taken into account.')); } diff --git a/lib/Alchemy/Phrasea/Controller/Root/LoginController.php b/lib/Alchemy/Phrasea/Controller/Root/LoginController.php index dc67e1d3f4..8e58803f1f 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/LoginController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/LoginController.php @@ -302,7 +302,7 @@ class LoginController extends Controller return; } - $collection = \collection::get_from_base_id($this->app, $baseId); + $collection = \collection::getByBaseId($this->app, $baseId); $registrationManipulator->createRegistration($user, $collection); $registrationsOK[$baseId] = $collection; }); diff --git a/lib/Alchemy/Phrasea/Core/Provider/BorderManagerServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/BorderManagerServiceProvider.php index 0038727dc9..d659a664fb 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/BorderManagerServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/BorderManagerServiceProvider.php @@ -70,7 +70,7 @@ class BorderManagerServiceProvider implements ServiceProviderInterface $collections = []; foreach ($checker['collections'] as $base_id) { try { - $collections[] = \collection::get_from_base_id($app, $base_id); + $collections[] = \collection::getByBaseId($app, $base_id); } catch (\Exception $e) { throw new \InvalidArgumentException('Invalid collection option'); } diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index d58db4bb8d..ba279d2867 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -12,7 +12,12 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\Collection\CollectionFactory; +use Alchemy\Phrasea\Collection\DbalCollectionReferenceRepository; +use Alchemy\Phrasea\Collection\DbalCollectionRepository; +use Alchemy\Phrasea\Collection\CachedCollectionRepository; use Alchemy\Phrasea\Databox\CachingDataboxRepositoryDecorator; +use Alchemy\Phrasea\Databox\DataboxConnectionProvider; use Alchemy\Phrasea\Databox\DataboxFactory; use Alchemy\Phrasea\Databox\DbalDataboxRepository; use Alchemy\Phrasea\Databox\Field\DataboxFieldFactory; @@ -138,6 +143,23 @@ class RepositoriesServiceProvider implements ServiceProviderInterface $app['repo.fields.factory'] = $app->protect(function (\databox $databox) use ($app) { return new DbalDataboxFieldRepository($databox->get_connection(), new DataboxFieldFactory($app, $databox)); }); + + $app['repo.collection-references'] = $app->share(function (PhraseaApplication $app) { + return new DbalCollectionReferenceRepository($app->getApplicationBox()->get_connection()); + }); + + $app['repo.collections'] = $app->share(function (PhraseaApplication $app) { + $appbox = $app->getApplicationBox(); + $factory = new CollectionFactory($app); + $connectionProvider = new DataboxConnectionProvider($appbox); + $repository = new DbalCollectionRepository( + $connectionProvider, + $app['repo.collection-references'], + $factory + ); + + return new CachedCollectionRepository($repository, $app['cache'], 'collection_'); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Databox/DataboxConnectionProvider.php b/lib/Alchemy/Phrasea/Databox/DataboxConnectionProvider.php new file mode 100644 index 0000000000..a1601dd00d --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/DataboxConnectionProvider.php @@ -0,0 +1,23 @@ +applicationBox = $applicationBox; + } + + /** + * @param $databoxId + * @return \Doctrine\DBAL\Connection + */ + public function getConnection($databoxId) + { + return $this->applicationBox->get_databox($databoxId)->get_connection(); + } +} diff --git a/lib/Alchemy/Phrasea/Helper/User/Edit.php b/lib/Alchemy/Phrasea/Helper/User/Edit.php index 770433e307..8e528148e9 100644 --- a/lib/Alchemy/Phrasea/Helper/User/Edit.php +++ b/lib/Alchemy/Phrasea/Helper/User/Edit.php @@ -227,7 +227,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper 'users' => $this->users, 'users_serial' => implode(';', $this->users), 'base_id' => $this->base_id, - 'collection' => \collection::get_from_base_id($this->app, $this->base_id), + 'collection' => \collection::getByBaseId($this->app, $this->base_id), ]; } @@ -331,7 +331,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper 'users' => $this->users, 'users_serial' => implode(';', $this->users), 'base_id' => $this->base_id, - 'collection' => \collection::get_from_base_id($this->app, $this->base_id), + 'collection' => \collection::getByBaseId($this->app, $this->base_id), ]; } @@ -391,7 +391,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper 'users' => $this->users, 'users_serial' => implode(';', $this->users), 'base_id' => $this->base_id, - 'collection' => \collection::get_from_base_id($this->app, $this->base_id), + 'collection' => \collection::getByBaseId($this->app, $this->base_id), ]; } diff --git a/lib/Alchemy/Phrasea/Model/Entities/Feed.php b/lib/Alchemy/Phrasea/Model/Entities/Feed.php index 6f1c5a8a93..55a2156128 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/Feed.php +++ b/lib/Alchemy/Phrasea/Model/Entities/Feed.php @@ -302,7 +302,7 @@ class Feed implements FeedInterface public function getCollection(Application $app) { if ($this->getBaseId() !== null) { - return \collection::get_from_base_id($app, $this->getBaseId()); + return \collection::getByBaseId($app, $this->getBaseId()); } } diff --git a/lib/Alchemy/Phrasea/Model/Entities/LazaretFile.php b/lib/Alchemy/Phrasea/Model/Entities/LazaretFile.php index d05bfeec7c..bd3af97f0c 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/LazaretFile.php +++ b/lib/Alchemy/Phrasea/Model/Entities/LazaretFile.php @@ -211,7 +211,7 @@ class LazaretFile */ public function getCollection(Application $app) { - return \collection::get_from_base_id($app, $this->getBaseId()); + return \collection::getByBaseId($app, $this->getBaseId()); } /** diff --git a/lib/Alchemy/Phrasea/Model/Entities/Registration.php b/lib/Alchemy/Phrasea/Model/Entities/Registration.php index e00b82455f..6d7e08052f 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/Registration.php +++ b/lib/Alchemy/Phrasea/Model/Entities/Registration.php @@ -141,7 +141,7 @@ class Registration */ public function getCollection(Application $app) { - return \collection::get_from_base_id($app, $this->baseId); + return \collection::getByBaseId($app, $this->baseId); } /** diff --git a/lib/Alchemy/Phrasea/Out/Module/PDF.php b/lib/Alchemy/Phrasea/Out/Module/PDF.php index 1f69fb1076..f9a5e43408 100644 --- a/lib/Alchemy/Phrasea/Out/Module/PDF.php +++ b/lib/Alchemy/Phrasea/Out/Module/PDF.php @@ -350,7 +350,7 @@ class PDF } } - $collection = \collection::get_from_base_id($this->app, $rec->get_base_id()); + $collection = \collection::getByBaseId($this->app, $rec->get_base_id()); $vn = ""; if (false !== $str = simplexml_load_string($collection->get_prefs())) { diff --git a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php index 50ec3f127b..2adaca141c 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php +++ b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php @@ -480,7 +480,7 @@ class SearchEngineOptions break; case in_array($key, ['collections', 'business_fields']): $value = array_map(function ($base_id) use ($app) { - return \collection::get_from_base_id($app, $base_id); + return \collection::getByBaseId($app, $base_id); }, $value); break; } @@ -571,7 +571,7 @@ class SearchEngineOptions $bas = []; foreach ($selected_bases as $bas_id) { try { - $bas[$bas_id] = \collection::get_from_base_id($app, $bas_id); + $bas[$bas_id] = \collection::getByBaseId($app, $bas_id); } catch (\Exception_Databox_CollectionNotFound $e) { // Ignore } diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php index 29376a82b6..5b4ef9c861 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/ArchiveJob.php @@ -867,7 +867,7 @@ class ArchiveJob extends AbstractJob } try { - $collection = \collection::get_from_coll_id($app, $databox, (int) $cid); + $collection = \collection::getByCollectionId($app, $databox, (int) $cid); if ($captionFileName === null) { $story = $this->createStory($app, $collection, $path . '/' . $representationFileName, null, $stat0, $stat1); } else { @@ -1200,7 +1200,7 @@ class ArchiveJob extends AbstractJob } try { - $collection = \collection::get_from_coll_id($app, $databox, (int) $cid); + $collection = \collection::getByCollectionId($app, $databox, (int) $cid); if ($captionFileName === null) { $this->createRecord($app, $collection, $path . '/' . $file, null, $grp_rid, null, $stat0, $stat1); diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/EmptyCollectionJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/EmptyCollectionJob.php index b788ad8b08..6f4ff51027 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/EmptyCollectionJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/EmptyCollectionJob.php @@ -61,7 +61,7 @@ class EmptyCollectionJob extends AbstractJob $baseId = (string) $settings->bas_id; - $collection = \collection::get_from_base_id($app, $baseId); + $collection = \collection::getByBaseId($app, $baseId); $collection->empty_collection(200); if (0 === $collection->get_record_amount()) { diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/RecordMoverJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/RecordMoverJob.php index 13b79f4727..723bea85f3 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/RecordMoverJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/RecordMoverJob.php @@ -82,7 +82,7 @@ class RecordMoverJob extends AbstractJob case 'UPDATE': // change collection ? if (array_key_exists('coll', $row)) { - $coll = \collection::get_from_coll_id($app, $databox, $row['coll']); + $coll = \collection::getByCollectionId($app, $databox, $row['coll']); $rec->move_to_collection($coll, $app['phraseanet.appbox']); if ($logsql) { $this->log('debug', sprintf("on sbas %s move rid %s to coll %s \n", $row['sbas_id'], $row['record_id'], $coll->get_coll_id())); diff --git a/lib/classes/ACL.php b/lib/classes/ACL.php index fbd87f10ef..8c41a56fa7 100644 --- a/lib/classes/ACL.php +++ b/lib/classes/ACL.php @@ -717,7 +717,7 @@ class ACL implements cache_cacheableInterface } try { - $ret[$base_id] = collection::get_from_base_id($this->app, $base_id); + $ret[$base_id] = collection::getByBaseId($this->app, $base_id); } catch (\Exception $e) { } @@ -1655,7 +1655,7 @@ class ACL implements cache_cacheableInterface $collections = []; foreach ($rs as $row) { - $collections[] = \collection::get_from_base_id($this->app, $row['base_id']); + $collections[] = \collection::getByBaseId($this->app, $row['base_id']); } return $collections; diff --git a/lib/classes/appbox.php b/lib/classes/appbox.php index 5934bfab2e..6df141463b 100644 --- a/lib/classes/appbox.php +++ b/lib/classes/appbox.php @@ -16,7 +16,6 @@ use Alchemy\Phrasea\Core\Version\AppboxVersionRepository; use Alchemy\Phrasea\Databox\DataboxRepository; use Doctrine\ORM\Tools\SchemaTool; use MediaAlchemyst\Alchemyst; -use MediaAlchemyst\Specification\Image as ImageSpecification; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\File\File as SymfoFile; use Symfony\Component\Finder\Finder; @@ -257,9 +256,13 @@ class appbox extends base return $this->databoxes; } + /** + * @param int $sbas_id + * @return databox + */ public function get_databox($sbas_id) { - $databoxes = $this->get_databoxes(); + $databoxes = $this->getDataboxRepository()->findAll(); if (!isset($databoxes[$sbas_id]) && !array_key_exists($sbas_id, $databoxes)) { throw new NotFoundHttpException('Databox `' . $sbas_id . '` not found'); diff --git a/lib/classes/collection.php b/lib/classes/collection.php index d3c7516f10..cefde0d517 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -10,6 +10,8 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\CollectionReference; +use Alchemy\Phrasea\Collection\CollectionRepository; use Alchemy\Phrasea\Core\Event\Collection\CollectionEvent; use Alchemy\Phrasea\Core\Event\Collection\CollectionEvents; use Alchemy\Phrasea\Core\Event\Collection\CreatedEvent; @@ -23,125 +25,279 @@ use Symfony\Component\HttpFoundation\File\File; class collection implements cache_cacheableInterface, ThumbnailedElement { - protected $base_id; - protected $sbas_id; - protected $coll_id; - protected $available = false; - protected $name; - protected $prefs; - protected $pub_wm; - protected $labels = []; - private static $_logos = []; - private static $_stamps = []; - private static $_watermarks = []; - private static $_presentations = []; - private static $_collections = []; - protected $databox; - protected $is_active; - protected $binary_logo; - protected $ord; - protected $app; const PIC_LOGO = 'minilogos'; const PIC_WM = 'wm'; const PIC_STAMP = 'stamp'; const PIC_PRESENTATION = 'presentation'; - protected function __construct(Application $app, $coll_id, databox $databox) + private static $_logos = []; + private static $_stamps = []; + private static $_watermarks = []; + private static $_presentations = []; + private static $_collections = []; + + private static function getNewOrder(Connection $conn, $sbas_id) { - $this->app = $app; - $this->databox = $databox; - $this->sbas_id = (int) $databox->get_sbas_id(); - $this->coll_id = (int) $coll_id; - $this->load(); - - return $this; - } - - private function dispatch($eventName, CollectionEvent $event) - { - $this->app['dispatcher']->dispatch($eventName, $event); - } - - protected function load() - { - try { - $datas = $this->get_data_from_cache(); - if (!is_array($datas)) { - throw new \Exception('Collection could not be retrieved from cache'); - } - $this->is_active = $datas['is_active']; - $this->base_id = $datas['base_id']; - $this->available = $datas['available']; - $this->pub_wm = $datas['pub_wm']; - $this->name = $datas['name']; - $this->ord = $datas['ord']; - $this->prefs = $datas['prefs']; - $this->labels = $datas['labels']; - - return $this; - } catch (\Exception $e) { - - } - - $connbas = $this->databox->get_connection(); - $sql = 'SELECT - asciiname, prefs, pub_wm, coll_id, - label_en, label_fr, label_de, label_nl - FROM coll WHERE coll_id = :coll_id'; - $stmt = $connbas->prepare($sql); - $stmt->execute([':coll_id' => $this->coll_id]); - $row = $stmt->fetch(PDO::FETCH_ASSOC); + $sql = "SELECT GREATEST(0, MAX(ord)) + 1 AS ord FROM bas WHERE sbas_id = :sbas_id"; + $stmt = $conn->prepare($sql); + $stmt->execute([':sbas_id' => $sbas_id]); + $ord = $stmt->fetch(\PDO::FETCH_ASSOC); $stmt->closeCursor(); - if ( ! $row) - throw new Exception('Unknown collection ' . $this->coll_id . ' on ' . $this->databox->get_dbname()); + return $ord['ord'] ?: 1; + } + public static function create(Application $app, databox $databox, appbox $appbox, $name, User $user = null) + { + $sbas_id = $databox->get_sbas_id(); + $connbas = $databox->get_connection(); + $conn = $appbox->get_connection(); + $new_bas = false; + + $prefs = << + + 0 + + +EOT; + + $sql = "INSERT INTO coll (coll_id, asciiname, prefs, logo) + VALUES (null, :name, :prefs, '')"; + + $params = [ + ':name' => $name, + 'prefs' => $prefs, + ]; + + $stmt = $connbas->prepare($sql); + $stmt->execute($params); + $stmt->closeCursor(); + + $new_id = (int) $connbas->lastInsertId(); + + $sql = "INSERT INTO bas (base_id, active, ord, server_coll_id, sbas_id, aliases) + VALUES + (null, 1, :ord, :server_coll_id, :sbas_id, '')"; + $stmt = $conn->prepare($sql); + $stmt->execute([ + ':server_coll_id' => $new_id, + ':sbas_id' => $sbas_id, + ':ord' => self::getNewOrder($conn, $sbas_id), + ]); + $stmt->closeCursor(); + + $new_bas = $conn->lastInsertId(); + $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); + $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); + + phrasea::reset_baseDatas($appbox); + + $collection = self::getByCollectionId($app, $databox, $new_id); + + if (null !== $user) { + $collection->set_admin($new_bas, $user); + } + + $app['dispatcher']->dispatch(CollectionEvents::CREATED, new CreatedEvent($collection)); + + return $collection; + } + + public static function mount_collection(Application $app, databox $databox, $coll_id, User $user) + { + $sql = "INSERT INTO bas (base_id, active, server_coll_id, sbas_id, aliases, ord) + VALUES + (null, 1, :server_coll_id, :sbas_id, '', :ord)"; + $stmt = $databox->get_appbox()->get_connection()->prepare($sql); + $stmt->execute([ + ':server_coll_id' => $coll_id, + ':sbas_id' => $databox->get_sbas_id(), + ':ord' => self::getNewOrder($databox->get_appbox()->get_connection(), $databox->get_sbas_id()), + ]); + $stmt->closeCursor(); + + $new_bas = $databox->get_appbox()->get_connection()->lastInsertId(); + $databox->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); + + $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); + + cache_databox::update($app, $databox->get_sbas_id(), 'structure'); + + phrasea::reset_baseDatas($databox->get_appbox()); + + $coll = self::getByBaseId($app, $new_bas); + $coll->set_admin($new_bas, $user); + + return $new_bas; + } + + public static function getLogo($base_id, Application $app, $printname = false) + { + $base_id_key = $base_id . '_' . ($printname ? '1' : '0'); + + if ( ! isset(self::$_logos[$base_id_key])) { + + if (is_file($app['root.path'] . '/config/minilogos/' . $base_id)) { + $name = phrasea::bas_labels($base_id, $app); + self::$_logos[$base_id_key] = ''; + } elseif ($printname) { + self::$_logos[$base_id_key] = phrasea::bas_labels($base_id, $app); + } + } + + return isset(self::$_logos[$base_id_key]) ? self::$_logos[$base_id_key] : ''; + } + + public static function getWatermark($base_id) + { + if ( ! isset(self::$_watermarks['base_id'])) { + + if (is_file(__DIR__ . '/../../config/wm/' . $base_id)) + self::$_watermarks['base_id'] = ''; + } + + return isset(self::$_watermarks['base_id']) ? self::$_watermarks['base_id'] : ''; + } + + public static function getPresentation($base_id) + { + if ( ! isset(self::$_presentations['base_id'])) { + + if (is_file(__DIR__ . '/../../config/presentation/' . $base_id)) + self::$_presentations['base_id'] = ''; + } + + return isset(self::$_presentations['base_id']) ? self::$_presentations['base_id'] : ''; + } + + public static function getStamp($base_id) + { + if ( ! isset(self::$_stamps['base_id'])) { + + if (is_file(__DIR__ . '/../../config/stamp/' . $base_id)) + self::$_stamps['base_id'] = ''; + } + + return isset(self::$_stamps['base_id']) ? self::$_stamps['base_id'] : ''; + } + + public static function purge() + { + self::$_collections = []; + } + + /** + * @param Application $app + * @param int $base_id + * @return collection + */ + public static function getByBaseId(Application $app, $base_id) + { + /** @var CollectionRepository $repository */ + $repository = $app['repo.collections']; + $collection = $repository->find($base_id); + + if (! $collection) { + throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); + } + + if (!$app['conf.restrictions']->isCollectionAvailable($collection)) { + throw new Exception_Databox_CollectionNotFound('Collection `' . $collection->get_base_id() . '` is not available here.'); + } + + return $collection; + } + + /** + * @param Application $app + * @param databox $databox + * @param int $coll_id + * @return collection + */ + public static function getByCollectionId(Application $app, databox $databox, $coll_id) + { + assert(is_int($coll_id)); + + /** @var CollectionRepository $repository */ + $repository = $app['repo.collections']; + $collection = $repository->findByCollectionId($databox->get_sbas_id(), $coll_id); + + if (! $collection) { + throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); + } + + if (!$app['conf.restrictions']->isCollectionAvailable($collection)) { + throw new Exception_Databox_CollectionNotFound('Collection `' . $collection->get_base_id() . '` is not available here.'); + } + + return $collection; + } + + /** + * @var CollectionReference + */ + protected $reference; + + /** + * @var string + */ + protected $name; + + /** + * @var string + */ + protected $preferences; + + /** + * @var string + */ + protected $pub_wm; + + /** + * @var string[] + */ + protected $labels = []; + + /** + * @var databox + */ + protected $databox; + + /** + * @var int[]|string + */ + protected $binary_logo; + + /** + * @var Application + */ + protected $app; + + public function __construct(Application $app, $baseId, CollectionReference $reference, array $row) + { + $this->app = $app; + $this->databox = $app->getApplicationBox()->get_databox($reference->getDataboxId()); + + $this->reference = $reference; + + $this->name = $row['asciiname']; $this->available = true; $this->pub_wm = $row['pub_wm']; - $this->name = $row['asciiname']; - $this->prefs = $row['prefs']; + $this->preferences = $row['prefs']; $this->labels = [ 'fr' => $row['label_fr'], 'en' => $row['label_en'], 'de' => $row['label_de'], 'nl' => $row['label_nl'], ]; + } - $conn = $this->app->getApplicationBox()->get_connection(); - - $sql = 'SELECT server_coll_id, sbas_id, base_id, active, ord FROM bas - WHERE server_coll_id = :coll_id AND sbas_id = :sbas_id'; - - $stmt = $conn->prepare($sql); - $stmt->execute([':coll_id' => $this->coll_id, ':sbas_id' => $this->databox->get_sbas_id()]); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $this->is_active = false; - - if ($row) { - $this->is_active = ! ! $row['active']; - $this->base_id = (int) $row['base_id']; - $this->ord = (int) $row['ord']; - } - - $stmt->closeCursor(); - - $datas = [ - 'is_active' => $this->is_active - , 'base_id' => $this->base_id - , 'available' => $this->available - , 'pub_wm' => $this->pub_wm - , 'name' => $this->name - , 'ord' => $this->ord - , 'prefs' => $this->prefs - , 'labels' => $this->labels - ]; - - $this->set_data_to_cache($datas); - - return $this; + private function dispatch($eventName, CollectionEvent $event) + { + $this->app['dispatcher']->dispatch($eventName, $event); } public function enable(appbox $appbox) @@ -162,7 +318,7 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function get_ord() { - return $this->ord; + return $this->reference->getDisplayIndex(); } public function set_ord($ord) @@ -171,6 +327,8 @@ class collection implements cache_cacheableInterface, ThumbnailedElement $this->delete_data_from_cache(); $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); + $this->reference->setDisplayIndex($ord); + return $this; } @@ -186,6 +344,8 @@ class collection implements cache_cacheableInterface, ThumbnailedElement $this->databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); + $this->reference->disable(); + return $this; } @@ -211,9 +371,12 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return $this; } + /** + * @return bool + */ public function is_active() { - return $this->is_active; + return $this->reference->isActive(); } /** @@ -225,16 +388,26 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return $this->databox; } + /** + * @return \Doctrine\DBAL\Connection + */ public function get_connection() { return $this->databox->get_connection(); } + /** + * @return int + */ public function getRootIdentifier() { - return $this->base_id; + return $this->reference->getBaseId(); } + /** + * @param string $thumbnailType + * @param File $file + */ public function updateThumbnail($thumbnailType, File $file = null) { switch ($thumbnailType) { @@ -254,7 +427,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement } } - public function set_public_presentation($publi) { if (in_array($publi, ['none', 'wm', 'stamp'])) { @@ -344,7 +516,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function get_record_details() { - $sql = "SELECT record.coll_id,name,COALESCE(asciiname, CONCAT('_',record.coll_id)) AS asciiname, SUM(1) AS n, SUM(size) AS size FROM record NATURAL JOIN subdef @@ -386,7 +557,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function reset_watermark() { - $sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id) WHERE r.coll_id = :coll_id AND r.type="image" AND s.name="preview"'; @@ -403,7 +573,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function reset_stamp($record_id = null) { - $sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id) WHERE r.coll_id = :coll_id AND r.type="image" AND s.name IN ("preview", "document")'; @@ -463,81 +632,38 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return $this->binary_logo; } - /** - * - * @param Application $app - * @param int $base_id - * @return collection - */ - public static function get_from_base_id(Application $app, $base_id) - { - $coll_id = phrasea::collFromBas($app, $base_id); - $sbas_id = phrasea::sbasFromBas($app, $base_id); - if (! $sbas_id || ! $coll_id) { - throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); - } - $databox = $app->findDataboxById($sbas_id); - - return self::get_from_coll_id($app, $databox, $coll_id); - } - - /** - * - * @param Application $app - * @param databox $databox - * @param int $coll_id - * @return collection - */ - public static function get_from_coll_id(Application $app, databox $databox, $coll_id) - { - assert(is_int($coll_id)); - - $key = sprintf('%d_%d', $databox->get_sbas_id(), $coll_id); - if (!isset(self::$_collections[$key])) { - $collection = new self($app, $coll_id, $databox); - - if (!$app['conf.restrictions']->isCollectionAvailable($collection)) { - throw new Exception_Databox_CollectionNotFound('Collection `' . $collection->get_base_id() . '` is not available here.'); - } - - self::$_collections[$key] = $collection; - } - - return self::$_collections[$key]; - } - public function get_base_id() { - return $this->base_id; + return $this->reference->getBaseId(); } public function get_sbas_id() { - return $this->sbas_id; + return $this->reference->getDataboxId(); } public function get_coll_id() { - return $this->coll_id; + return $this->reference->getCollectionId(); } public function get_prefs() { - return $this->prefs; + return $this->preferences; } public function set_prefs(DOMDocument $dom) { - $this->prefs = $dom->saveXML(); + $this->preferences = $dom->saveXML(); $sql = "UPDATE coll SET prefs = :prefs WHERE coll_id = :coll_id"; $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':prefs' => $this->prefs, ':coll_id' => $this->get_coll_id()]); + $stmt->execute([':prefs' => $this->preferences, ':coll_id' => $this->get_coll_id()]); $stmt->closeCursor(); $this->delete_data_from_cache(); - return $this->prefs; + return $this->preferences; } public function get_name() @@ -592,73 +718,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return $this; } - private static function getNewOrder(Connection $conn, $sbas_id) - { - $sql = "SELECT GREATEST(0, MAX(ord)) + 1 AS ord FROM bas WHERE sbas_id = :sbas_id"; - $stmt = $conn->prepare($sql); - $stmt->execute([':sbas_id' => $sbas_id]); - $ord = $stmt->fetch(\PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - return $ord['ord'] ?: 1; - } - - public static function create(Application $app, databox $databox, appbox $appbox, $name, User $user = null) - { - $sbas_id = $databox->get_sbas_id(); - $connbas = $databox->get_connection(); - $conn = $appbox->get_connection(); - $new_bas = false; - - $prefs = ' - - 0 - - - '; - - $sql = "INSERT INTO coll (coll_id, asciiname, prefs, logo) - VALUES (null, :name, :prefs, '')"; - - $params = [ - ':name' => $name, - 'prefs' => $prefs, - ]; - - $stmt = $connbas->prepare($sql); - $stmt->execute($params); - $stmt->closeCursor(); - - $new_id = (int) $connbas->lastInsertId(); - - $sql = "INSERT INTO bas (base_id, active, ord, server_coll_id, sbas_id, aliases) - VALUES - (null, 1, :ord, :server_coll_id, :sbas_id, '')"; - $stmt = $conn->prepare($sql); - $stmt->execute([ - ':server_coll_id' => $new_id, - ':sbas_id' => $sbas_id, - ':ord' => self::getNewOrder($conn, $sbas_id), - ]); - $stmt->closeCursor(); - - $new_bas = $conn->lastInsertId(); - $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); - - phrasea::reset_baseDatas($appbox); - - $collection = self::get_from_coll_id($app, $databox, $new_id); - - if (null !== $user) { - $collection->set_admin($new_bas, $user); - } - - $app['dispatcher']->dispatch(CollectionEvents::CREATED, new CreatedEvent($collection)); - - return $collection; - } - public function set_admin($base_id, User $user) { @@ -687,86 +746,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return true; } - public static function mount_collection(Application $app, databox $databox, $coll_id, User $user) - { - - $sql = "INSERT INTO bas (base_id, active, server_coll_id, sbas_id, aliases, ord) - VALUES - (null, 1, :server_coll_id, :sbas_id, '', :ord)"; - $stmt = $databox->get_appbox()->get_connection()->prepare($sql); - $stmt->execute([ - ':server_coll_id' => $coll_id, - ':sbas_id' => $databox->get_sbas_id(), - ':ord' => self::getNewOrder($databox->get_appbox()->get_connection(), $databox->get_sbas_id()), - ]); - $stmt->closeCursor(); - - $new_bas = $databox->get_appbox()->get_connection()->lastInsertId(); - $databox->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); - - $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - - cache_databox::update($app, $databox->get_sbas_id(), 'structure'); - - phrasea::reset_baseDatas($databox->get_appbox()); - - $coll = self::get_from_base_id($app, $new_bas); - $coll->set_admin($new_bas, $user); - - return $new_bas; - } - - public static function getLogo($base_id, Application $app, $printname = false) - { - $base_id_key = $base_id . '_' . ($printname ? '1' : '0'); - - if ( ! isset(self::$_logos[$base_id_key])) { - - if (is_file($app['root.path'] . '/config/minilogos/' . $base_id)) { - $name = phrasea::bas_labels($base_id, $app); - self::$_logos[$base_id_key] = ''; - } elseif ($printname) { - self::$_logos[$base_id_key] = phrasea::bas_labels($base_id, $app); - } - } - - return isset(self::$_logos[$base_id_key]) ? self::$_logos[$base_id_key] : ''; - } - - public static function getWatermark($base_id) - { - if ( ! isset(self::$_watermarks['base_id'])) { - - if (is_file(__DIR__ . '/../../config/wm/' . $base_id)) - self::$_watermarks['base_id'] = ''; - } - - return isset(self::$_watermarks['base_id']) ? self::$_watermarks['base_id'] : ''; - } - - public static function getPresentation($base_id) - { - if ( ! isset(self::$_presentations['base_id'])) { - - if (is_file(__DIR__ . '/../../config/presentation/' . $base_id)) - self::$_presentations['base_id'] = ''; - } - - return isset(self::$_presentations['base_id']) ? self::$_presentations['base_id'] : ''; - } - - public static function getStamp($base_id) - { - if ( ! isset(self::$_stamps['base_id'])) { - - if (is_file(__DIR__ . '/../../config/stamp/' . $base_id)) - self::$_stamps['base_id'] = ''; - } - - return isset(self::$_stamps['base_id']) ? self::$_stamps['base_id'] : ''; - } - public function get_cache_key($option = null) { return 'collection_' . $this->coll_id . ($option ? '_' . $option : ''); @@ -787,11 +766,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return $this->databox->delete_data_from_cache($this->get_cache_key($option)); } - public static function purge() - { - self::$_collections = []; - } - /** * Tells whether registration is activated for provided collection or not. * diff --git a/lib/classes/databox.php b/lib/classes/databox.php index c8e20e22f0..485e8f21d1 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\CollectionRepository; use Alchemy\Phrasea\Core\Connection\ConnectionSettings; use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Core\Version\DataboxVersionRepository; @@ -151,69 +152,30 @@ class databox extends base implements \Alchemy\Phrasea\Core\Thumbnail\Thumbnaile */ public function get_collections() { - $ret = []; + static $collections; - foreach ($this->get_available_collections() as $coll_id) { - $ret[] = collection::get_from_coll_id($this->app, $this, $coll_id); + if ($collections === null) { + /** @var CollectionRepository $collectionsRepository */ + $collectionsRepository = $this->app['repo.collections']; + $collections = $collectionsRepository->findAllByDatabox($this->get_sbas_id()); } - return $ret; + return $collections; } public function get_collection_unique_ids() { - static $base_ids; + static $collectionsIds; - if (isset($base_ids)) { - return $base_ids; - } + if ($collectionsIds === null) { + $collectionsIds = []; - $conn = $this->get_appbox()->get_connection(); - $sql = "SELECT b.base_id FROM bas b WHERE b.sbas_id = :sbas_id AND b.active = '1' ORDER BY b.ord ASC"; - $stmt = $conn->prepare($sql); - $stmt->execute([':sbas_id' => $this->id]); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $base_ids = []; - foreach ($rs as $row) { - $base_ids[] = (int) $row['base_id']; - } - - return $base_ids; - } - - protected function get_available_collections() - { - try { - $data = $this->get_data_from_cache(self::CACHE_COLLECTIONS); - if (is_array($data)) { - return $data; + foreach ($this->get_collections() as $collection) { + $collectionsIds[] = $collection->get_base_id(); } - } catch (\Exception $e) { - } - $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 - AND b.active = '1' - ORDER BY s.ord ASC, b.ord,b.base_id ASC"; - $stmt = $conn->prepare($sql); - $stmt->execute([':sbas_id' => $this->id]); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $ret = []; - - foreach ($rs as $row) { - $ret[] = (int) $row['server_coll_id']; - } - - $this->set_data_to_cache($ret, self::CACHE_COLLECTIONS); - - return $ret; + return $collectionsIds; } /** diff --git a/lib/classes/patch/370alpha7a.php b/lib/classes/patch/370alpha7a.php index f728e2132b..ebd5145426 100644 --- a/lib/classes/patch/370alpha7a.php +++ b/lib/classes/patch/370alpha7a.php @@ -110,7 +110,7 @@ class patch_370alpha7a extends patchAbstract $media = $app->getMediaFromUri($filePath); - $collection = \collection::get_from_base_id($app, $row['base_id']); + $collection = \collection::getByBaseId($app, $row['base_id']); $borderFile = new \Alchemy\Phrasea\Border\File($app, $media, $collection); diff --git a/lib/classes/patch/390alpha13a.php b/lib/classes/patch/390alpha13a.php index d0b7ca7118..3b96e50b46 100644 --- a/lib/classes/patch/390alpha13a.php +++ b/lib/classes/patch/390alpha13a.php @@ -91,7 +91,7 @@ class patch_390alpha13a implements patchInterface } try { - $collection = \collection::get_from_base_id($app, $row['base_id']); + $collection = \collection::getByBaseId($app, $row['base_id']); } catch (\Exception $e) { $app['monolog']->addInfo(sprintf( 'Patch %s : Registration for user (%s) could not be turn into doctrine entity as base with id (%s) could not be found.', diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 37b0cd18df..d155ab7ce9 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -300,7 +300,7 @@ class record_adapter implements RecordInterface, cache_cacheableInterface */ public function get_collection() { - return \collection::get_from_coll_id($this->app, $this->databox, $this->collection_id); + return \collection::getByCollectionId($this->app, $this->databox, $this->collection_id); } /** diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php index f1a9d3e801..5ad9553753 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php @@ -154,7 +154,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $json = $this->getJson(self::$DI['client']->getResponse()); $this->assertTrue($json->success); - $collection = $collection = \collection::get_from_base_id(self::$DI['app'], self::$DI['collection']->get_base_id()); + $collection = $collection = \collection::getByBaseId(self::$DI['app'], self::$DI['collection']->get_base_id()); $this->assertTrue( ! ! strrpos($collection->get_prefs(), 'my_new_value')); unset($collection); } @@ -212,7 +212,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $json = $this->getJson(self::$DI['client']->getResponse()); $this->assertTrue($json->success); - $collection = \collection::get_from_base_id(self::$DI['app'], self::$DI['collection']->get_base_id()); + $collection = \collection::getByBaseId(self::$DI['app'], self::$DI['collection']->get_base_id()); $this->assertTrue($collection->is_active()); unset($collection); } @@ -252,7 +252,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $json = $this->getJson(self::$DI['client']->getResponse()); $this->assertTrue($json->success); - $collection = \collection::get_from_base_id(self::$DI['app'], self::$DI['collection']->get_base_id()); + $collection = \collection::getByBaseId(self::$DI['app'], self::$DI['collection']->get_base_id()); $this->assertFalse($collection->is_active()); unset($collection); } @@ -335,7 +335,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $json = $this->getJson(self::$DI['client']->getResponse()); $this->assertTrue($json->success); - $collection = \collection::get_from_base_id(self::$DI['app'], self::$DI['collection']->get_base_id()); + $collection = \collection::getByBaseId(self::$DI['app'], self::$DI['collection']->get_base_id()); $this->assertNotNull($collection->get_pub_wm()); unset($collection); } @@ -832,7 +832,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $json = $this->getJson(self::$DI['client']->getResponse()); $this->assertTrue($json->success); try { - \collection::get_from_base_id(self::$DI['app'], $collection->get_base_id()); + \collection::getByBaseId(self::$DI['app'], $collection->get_base_id()); $this->fail('Collection not deleted'); } catch (\Exception $e) { @@ -902,7 +902,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $this->assertTrue($json->success); try { - \collection::get_from_base_id(self::$DI['app'], $collection->get_base_id()); + \collection::getByBaseId(self::$DI['app'], $collection->get_base_id()); $this->fail('Collection not unmounted'); } catch (\Exception_Databox_CollectionNotFound $e) { diff --git a/tests/classes/ACLTest.php b/tests/classes/ACLTest.php index f73248c905..e259569347 100644 --- a/tests/classes/ACLTest.php +++ b/tests/classes/ACLTest.php @@ -494,7 +494,7 @@ class ACLTest extends \PhraseanetTestCase foreach ($bases as $base_id) { try { - $collection = collection::get_from_base_id(self::$DI['app'], $base_id); + $collection = collection::getByBaseId(self::$DI['app'], $base_id); $this->assertTrue($collection instanceof collection); $this->assertEquals($base_id, $collection->get_base_id()); unset($collection); diff --git a/tests/classes/PhraseanetTestCase.php b/tests/classes/PhraseanetTestCase.php index da52f18e1e..16b81f8710 100644 --- a/tests/classes/PhraseanetTestCase.php +++ b/tests/classes/PhraseanetTestCase.php @@ -196,15 +196,15 @@ abstract class PhraseanetTestCase extends WebTestCase }); self::$DI['collection'] = self::$DI->share(function ($DI) { - return collection::get_from_base_id($DI['app'], self::$fixtureIds['collection']['coll']); + return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll']); }); self::$DI['collection_no_access'] = self::$DI->share(function ($DI) { - return collection::get_from_base_id($DI['app'], self::$fixtureIds['collection']['coll_no_access']); + return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll_no_access']); }); self::$DI['collection_no_access_by_status'] = self::$DI->share(function ($DI) { - return collection::get_from_base_id($DI['app'], self::$fixtureIds['collection']['coll_no_status']); + return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll_no_status']); }); self::$DI['lazaret_1'] = self::$DI->share(function ($DI) { diff --git a/tests/classes/collectionTest.php b/tests/classes/collectionTest.php index 97709f5741..7bc607cd76 100644 --- a/tests/classes/collectionTest.php +++ b/tests/classes/collectionTest.php @@ -175,7 +175,7 @@ class collectionTest extends \PhraseanetTestCase public function testGet_from_coll_id() { - $temp_coll = collection::get_from_coll_id(self::$DI['app'], self::$object->get_databox(), self::$object->get_coll_id()); + $temp_coll = collection::getByCollectionId(self::$DI['app'], self::$object->get_databox(), self::$object->get_coll_id()); $this->assertEquals(self::$object->get_coll_id(), $temp_coll->get_coll_id()); $this->assertEquals(self::$object->get_base_id(), $temp_coll->get_base_id()); } From 2623f39488a495e4b0fe2dff1591b18af632a4ee Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 12:25:30 +0200 Subject: [PATCH 02/17] Add de/serialization methods for collection caching --- .../Collection/CachedCollectionRepository.php | 37 +++++++++++++++-- .../Phrasea/Collection/CollectionFactory.php | 12 ++++-- .../Collection/DbalCollectionRepository.php | 6 +-- .../Provider/RepositoriesServiceProvider.php | 2 +- lib/classes/collection.php | 40 +++++++++++++++---- 5 files changed, 78 insertions(+), 19 deletions(-) diff --git a/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php index fd918a53cd..7dcf00aae4 100644 --- a/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php @@ -9,20 +9,41 @@ */ namespace Alchemy\Phrasea\Collection; +use Alchemy\Phrasea\Application; use Doctrine\Common\Cache\Cache; final class CachedCollectionRepository implements CollectionRepository { - /** @var CollectionRepository */ + /** + * @var Application + */ + private $app; + + /** + * @var CollectionRepository + */ private $repository; - /** @var Cache */ + + /** + * @var Cache + */ private $cache; - /** @var string */ + + /** + * @var string + */ private $cacheKey; - public function __construct(CollectionRepository $repository, Cache $cache, $cacheKey) + /** + * @param Application $application + * @param CollectionRepository $repository + * @param Cache $cache + * @param $cacheKey + */ + public function __construct(Application $application, CollectionRepository $repository, Cache $cache, $cacheKey) { + $this->app = $application; $this->repository = $repository; $this->cache = $cache; $this->cacheKey = $cacheKey; @@ -40,6 +61,10 @@ final class CachedCollectionRepository implements CollectionRepository if ($collections === false) { $collections = $this->repository->findAllByDatabox($databoxId); $this->save($cacheKey, $collections); + } else { + foreach ($collections as $collection) { + $collection->hydrate($this->app); + } } return $collections; @@ -57,6 +82,8 @@ final class CachedCollectionRepository implements CollectionRepository if ($collection === false) { $collection = $this->repository->find($baseId); $this->save($cacheKey, $collection); + } else { + $collection->hydrate($this->app); } return $collection; @@ -75,6 +102,8 @@ final class CachedCollectionRepository implements CollectionRepository if ($collection === false) { $collection = $this->repository->findByCollectionId($databoxId, $collectionId); $this->save($cacheKey, $collection); + } else { + $collection->hydrate($this->app); } return $collection; diff --git a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php index bd3963fc76..18303e47df 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php @@ -21,21 +21,27 @@ class CollectionFactory } /** + * @param int $databoxId * @param CollectionReference $reference * @param array $row * @return \collection */ - public function create(CollectionReference $reference, array $row) + public function create($databoxId, CollectionReference $reference, array $row) { + if ($databoxId != $reference->getDataboxId()) { + throw new \InvalidArgumentException('Reference does not belong to given databoxId.'); + } + return new \collection($this->app, $reference->getBaseId(), $reference, $row); } /** + * @param int $databoxId * @param CollectionReference[] $collectionReferences * @param array $rows * @return array */ - public function createMany($collectionReferences, array $rows) + public function createMany($databoxId, $collectionReferences, array $rows) { Assertion::allIsInstanceOf($collectionReferences, CollectionReference::class); @@ -47,7 +53,7 @@ class CollectionFactory } foreach ($rows as $row) { - $collections[$row['coll_id']] = $this->create($indexedReferences[$row['coll_id']], $row); + $collections[$row['coll_id']] = $this->create($databoxId, $indexedReferences[$row['coll_id']], $row); } return $collections; diff --git a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php index 826894dcd3..729f47703c 100644 --- a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php @@ -53,7 +53,7 @@ class DbalCollectionRepository implements CollectionRepository $query = self::$query . sprintf(' WHERE coll_id IN (%s)', implode(', ', array_keys($params))); $rows = $connection->fetchAll($query, $params); - return $this->collectionFactory->createMany($references, $rows); + return $this->collectionFactory->createMany($databoxId, $references, $rows); } /** @@ -74,7 +74,7 @@ class DbalCollectionRepository implements CollectionRepository $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { - return $this->collectionFactory->create($reference, $row); + return $this->collectionFactory->create($reference->getDataboxId(), $reference, $row); } return null; @@ -99,7 +99,7 @@ class DbalCollectionRepository implements CollectionRepository $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { - return $this->collectionFactory->create($row['baseId'], $reference, $row); + return $this->collectionFactory->create($databoxId, $row['baseId'], $reference, $row); } return null; diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index ba279d2867..10611af301 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -158,7 +158,7 @@ class RepositoriesServiceProvider implements ServiceProviderInterface $factory ); - return new CachedCollectionRepository($repository, $app['cache'], 'collection_'); + return new CachedCollectionRepository($app, $repository, $app['cache'], 'collection_'); }); } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index cefde0d517..8fff1a3d64 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -236,6 +236,16 @@ EOT; return $collection; } + /** + * @var Application + */ + protected $app; + + /** + * @var databox + */ + protected $databox; + /** * @var CollectionReference */ @@ -261,21 +271,17 @@ EOT; */ protected $labels = []; - /** - * @var databox - */ - protected $databox; - /** * @var int[]|string */ protected $binary_logo; /** - * @var Application + * @param Application $app + * @param $baseId + * @param CollectionReference $reference + * @param array $row */ - protected $app; - public function __construct(Application $app, $baseId, CollectionReference $reference, array $row) { $this->app = $app; @@ -295,6 +301,24 @@ EOT; ]; } + public function __sleep() + { + return array( + 'reference', + 'name', + 'preferences', + 'pub_wm', + 'labels', + 'binary_logo' + ); + } + + public function hydrate(Application $app) + { + $this->app = $app; + $this->databox = $app->getApplicationBox()->get_databox($this->reference->getDataboxId()); + } + private function dispatch($eventName, CollectionEvent $event) { $this->app['dispatcher']->dispatch($eventName, $event); From 20355effe9c9c4e1ec9003daedcc9962462e69ea Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 12:47:03 +0200 Subject: [PATCH 03/17] Change CLI verbosity in tests --- circle.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/circle.yml b/circle.yml index 5dffbf57bc..60ed962bcd 100644 --- a/circle.yml +++ b/circle.yml @@ -33,12 +33,12 @@ database: override: - mysql -u ubuntu -e 'CREATE DATABASE update39_test;CREATE DATABASE ab_test;CREATE DATABASE db_test;SET @@global.sql_mode=STRICT_ALL_TABLES;SET @@global.max_allowed_packet=33554432;SET @@global.wait_timeout=999999;'; post: - - "./bin/developer system:uninstall" - - "./bin/setup system:install --email=test@phraseanet.com --password=test --db-host=127.0.0.1 --db-user=ubuntu --db-template=fr --db-password= --databox=db_test --appbox=ab_test --server-name=http://127.0.0.1 -y;" - - "./bin/developer ini:setup-tests-dbs" - - "./bin/console searchengine:index:create" - - "./bin/developer phraseanet:regenerate-sqlite" - - "./bin/developer phraseanet:generate-js-fixtures" + - "./bin/developer system:uninstall -vvv" + - "./bin/setup system:install -vvv --email=test@phraseanet.com --password=test --db-host=127.0.0.1 --db-user=ubuntu --db-template=fr --db-password= --databox=db_test --appbox=ab_test --server-name=http://127.0.0.1 -y;" + - "./bin/developer ini:setup-tests-dbs -vvv" + - "./bin/console searchengine:index:create -vvv" + - "./bin/developer phraseanet:regenerate-sqlite -vvv" + - "./bin/developer phraseanet:generate-js-fixtures -vvv" test: override: From 6f8545569fef468276d9fac7e11a498c20df643e Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 14:23:19 +0200 Subject: [PATCH 04/17] Fix undefined index --- circle.yml | 12 ++++++------ .../Phrasea/Collection/DbalCollectionRepository.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/circle.yml b/circle.yml index 60ed962bcd..7c3212781a 100644 --- a/circle.yml +++ b/circle.yml @@ -33,12 +33,12 @@ database: override: - mysql -u ubuntu -e 'CREATE DATABASE update39_test;CREATE DATABASE ab_test;CREATE DATABASE db_test;SET @@global.sql_mode=STRICT_ALL_TABLES;SET @@global.max_allowed_packet=33554432;SET @@global.wait_timeout=999999;'; post: - - "./bin/developer system:uninstall -vvv" - - "./bin/setup system:install -vvv --email=test@phraseanet.com --password=test --db-host=127.0.0.1 --db-user=ubuntu --db-template=fr --db-password= --databox=db_test --appbox=ab_test --server-name=http://127.0.0.1 -y;" - - "./bin/developer ini:setup-tests-dbs -vvv" - - "./bin/console searchengine:index:create -vvv" - - "./bin/developer phraseanet:regenerate-sqlite -vvv" - - "./bin/developer phraseanet:generate-js-fixtures -vvv" + - "./bin/developer system:uninstall -v" + - "./bin/setup system:install -v --email=test@phraseanet.com --password=test --db-host=127.0.0.1 --db-user=ubuntu --db-template=fr --db-password= --databox=db_test --appbox=ab_test --server-name=http://127.0.0.1 -y;" + - "./bin/developer ini:setup-tests-dbs -v" + - "./bin/console searchengine:index:create -v" + - "./bin/developer phraseanet:regenerate-sqlite -v" + - "./bin/developer phraseanet:generate-js-fixtures -v" test: override: diff --git a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php index 729f47703c..203cf47bee 100644 --- a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php @@ -99,7 +99,7 @@ class DbalCollectionRepository implements CollectionRepository $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { - return $this->collectionFactory->create($databoxId, $row['baseId'], $reference, $row); + return $this->collectionFactory->create($databoxId, $reference, $row); } return null; From 080aecd208c0eed4c27c28db447eddbb5e3d0e81 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 14:40:23 +0200 Subject: [PATCH 05/17] Fix undefined property --- lib/classes/collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 8fff1a3d64..1f4d10834b 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -772,7 +772,7 @@ EOT; public function get_cache_key($option = null) { - return 'collection_' . $this->coll_id . ($option ? '_' . $option : ''); + return 'collection_' . $this->get_coll_id() . ($option ? '_' . $option : ''); } public function get_data_from_cache($option = null) From bd57e04dc00f6b08005f8bb233658bb0c949a5f1 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 15:49:27 +0200 Subject: [PATCH 06/17] Add array cache collection repository --- .../ArrayCacheCollectionRepository.php | 90 +++++++++++++++++++ lib/classes/collection.php | 8 ++ 2 files changed, 98 insertions(+) create mode 100644 lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php diff --git a/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php new file mode 100644 index 0000000000..99c24811d7 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php @@ -0,0 +1,90 @@ +collectionRepository = $collectionRepository; + } + + private function putCollectionsInCache(array $collections) + { + foreach ($collections as $collection) { + $this->putCollectionInCache($collection); + } + } + + private function putCollectionInCache(\collection $collection = null) + { + if ($collection === null) { + return; + } + + $baseId = $collection->getReference()->getBaseId(); + $databoxId = $collection->getReference()->getDataboxId(); + $collectionId = $collection->getReference()->getCollectionId(); + + if (! isset($this->collectionCache[$databoxId])) { + $this->collectionCache[$databoxId] = []; + } + + $this->collectionCache[$databoxId][$collectionId] = $collection; + $this->baseIdMap[$baseId] = [ $databoxId, $collectionId ]; + } + + /** + * @param int $databoxId + * @return \collection[] + */ + public function findAllByDatabox($databoxId) + { + if (! isset($this->databoxFlags[$databoxId]) || $this->databoxFlags[$databoxId] !== true) { + $this->putCollectionsInCache($this->collectionRepository->findAllByDatabox($databoxId)); + $this->databoxFlags[$databoxId] = true; + } + + return $this->collectionCache[$databoxId]; + } + + /** + * @param int $baseId + * @return \collection|null + */ + public function find($baseId) + { + if (! isset($this->baseIdMap[$baseId])) { + $this->putCollectionInCache($this->collectionRepository->find($baseId)); + } + + list ($databoxId, $collectionId) = $this->baseIdMap[$baseId]; + + return $this->collectionCache[$databoxId][$collectionId]; + } + + /** + * @param int $databoxId + * @param int $collectionId + * @return \collection|null + */ + public function findByCollectionId($databoxId, $collectionId) + { + if (! isset($this->collectionCache[$databoxId][$collectionId])) { + $this->putCollectionInCache($this->collectionRepository->findByCollectionId($databoxId, $collectionId)); + } + + return $this->collectionCache[$databoxId][$collectionId]; + } +} diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 1f4d10834b..cf5b5962d5 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -319,6 +319,14 @@ EOT; $this->databox = $app->getApplicationBox()->get_databox($this->reference->getDataboxId()); } + /** + * @return CollectionReference + */ + public function getReference() + { + return $this->reference; + } + private function dispatch($eventName, CollectionEvent $event) { $this->app['dispatcher']->dispatch($eventName, $event); From d1b8b7f84e868212c9ed164df86b059b621dd4e0 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 16:03:15 +0200 Subject: [PATCH 07/17] Use array cache in DI --- .../Phrasea/Core/Provider/RepositoriesServiceProvider.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index 10611af301..fc7bb084c3 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\Collection\ArrayCacheCollectionRepository; use Alchemy\Phrasea\Collection\CollectionFactory; use Alchemy\Phrasea\Collection\DbalCollectionReferenceRepository; use Alchemy\Phrasea\Collection\DbalCollectionRepository; @@ -158,7 +159,9 @@ class RepositoriesServiceProvider implements ServiceProviderInterface $factory ); - return new CachedCollectionRepository($app, $repository, $app['cache'], 'collection_'); + $repository = new CachedCollectionRepository($app, $repository, $app['cache'], 'collection_'); + + return new ArrayCacheCollectionRepository($repository); }); } From 6b516618aac17935f213185aacd42e6693d80cbe Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 16:20:41 +0200 Subject: [PATCH 08/17] Fix some test failures --- .../ArrayCacheCollectionRepository.php | 37 ++++++++++++++++--- lib/classes/collection.php | 9 +++-- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php index 99c24811d7..98c19aa8a4 100644 --- a/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php @@ -45,6 +45,35 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->baseIdMap[$baseId] = [ $databoxId, $collectionId ]; } + private function getCollectionInCache($databoxId, $collectionId) + { + if (isset($this->collectionCache[$databoxId][$collectionId])) { + return $this->collectionCache[$databoxId][$collectionId]; + } + + return null; + } + + private function getCollectionInCacheByBaseId($baseId) + { + if (isset($this->baseIdMap[$baseId])) { + list ($databoxId, $collectionId) = $this->baseIdMap[$baseId]; + + return $this->getCollectionInCache($databoxId, $collectionId); + } + + return null; + } + + private function getCollectionsInCache($databoxId) + { + if (isset($this->collectionCache[$databoxId])) { + return $this->collectionCache[$databoxId]; + } + + return []; + } + /** * @param int $databoxId * @return \collection[] @@ -56,7 +85,7 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->databoxFlags[$databoxId] = true; } - return $this->collectionCache[$databoxId]; + return $this->getCollectionsInCache($databoxId); } /** @@ -69,9 +98,7 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->putCollectionInCache($this->collectionRepository->find($baseId)); } - list ($databoxId, $collectionId) = $this->baseIdMap[$baseId]; - - return $this->collectionCache[$databoxId][$collectionId]; + return $this->getCollectionInCacheByBaseId($baseId); } /** @@ -85,6 +112,6 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->putCollectionInCache($this->collectionRepository->findByCollectionId($databoxId, $collectionId)); } - return $this->collectionCache[$databoxId][$collectionId]; + return $this->getCollectionInCache($databoxId, $collectionId); } } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index cf5b5962d5..18ee44a755 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -339,7 +339,8 @@ EOT; $stmt->execute([':base_id' => $this->get_base_id()]); $stmt->closeCursor(); - $this->is_active = true; + $this->reference->enable(); + $this->delete_data_from_cache(); $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); $this->databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); @@ -370,14 +371,14 @@ EOT; $stmt = $appbox->get_connection()->prepare($sql); $stmt->execute([':base_id' => $this->get_base_id()]); $stmt->closeCursor(); - $this->is_active = false; + + $this->reference->disable(); + $this->delete_data_from_cache(); $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); $this->databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); - $this->reference->disable(); - return $this; } From 977e778b6182eb739962e634a262528fcc076925 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 18:48:53 +0200 Subject: [PATCH 09/17] Refactor collection repositories: use one instance per databox --- .../ArrayCacheCollectionRepository.php | 117 ------------------ .../Phrasea/Collection/CollectionFactory.php | 1 + .../Collection/CollectionRepository.php | 13 +- .../CollectionRepositoryFactory.php | 12 ++ .../CollectionRepositoryRegistry.php | 80 ++++++++++++ ...ArrayCachedCollectionRepositoryFactory.php | 34 +++++ .../CachedCollectionRepositoryFactory.php | 66 ++++++++++ .../DbalCollectionRepositoryFactory.php | 60 +++++++++ .../{ => Reference}/CollectionReference.php | 2 +- .../CollectionReferenceRepository.php | 2 +- .../DbalCollectionReferenceRepository.php | 2 +- .../ArrayCacheCollectionRepository.php | 50 ++++++++ .../CachedCollectionRepository.php | 49 ++------ .../DbalCollectionRepository.php | 45 +++---- .../Provider/RepositoriesServiceProvider.php | 35 ++++-- lib/classes/collection.php | 40 ++++-- lib/classes/databox.php | 13 +- 17 files changed, 407 insertions(+), 214 deletions(-) delete mode 100644 lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionRepositoryFactory.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php create mode 100644 lib/Alchemy/Phrasea/Collection/Factory/ArrayCachedCollectionRepositoryFactory.php create mode 100644 lib/Alchemy/Phrasea/Collection/Factory/CachedCollectionRepositoryFactory.php create mode 100644 lib/Alchemy/Phrasea/Collection/Factory/DbalCollectionRepositoryFactory.php rename lib/Alchemy/Phrasea/Collection/{ => Reference}/CollectionReference.php (97%) rename lib/Alchemy/Phrasea/Collection/{ => Reference}/CollectionReferenceRepository.php (92%) rename lib/Alchemy/Phrasea/Collection/{ => Reference}/DbalCollectionReferenceRepository.php (98%) create mode 100644 lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php rename lib/Alchemy/Phrasea/Collection/{ => Repository}/CachedCollectionRepository.php (52%) rename lib/Alchemy/Phrasea/Collection/{ => Repository}/DbalCollectionRepository.php (63%) diff --git a/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php deleted file mode 100644 index 98c19aa8a4..0000000000 --- a/lib/Alchemy/Phrasea/Collection/ArrayCacheCollectionRepository.php +++ /dev/null @@ -1,117 +0,0 @@ -collectionRepository = $collectionRepository; - } - - private function putCollectionsInCache(array $collections) - { - foreach ($collections as $collection) { - $this->putCollectionInCache($collection); - } - } - - private function putCollectionInCache(\collection $collection = null) - { - if ($collection === null) { - return; - } - - $baseId = $collection->getReference()->getBaseId(); - $databoxId = $collection->getReference()->getDataboxId(); - $collectionId = $collection->getReference()->getCollectionId(); - - if (! isset($this->collectionCache[$databoxId])) { - $this->collectionCache[$databoxId] = []; - } - - $this->collectionCache[$databoxId][$collectionId] = $collection; - $this->baseIdMap[$baseId] = [ $databoxId, $collectionId ]; - } - - private function getCollectionInCache($databoxId, $collectionId) - { - if (isset($this->collectionCache[$databoxId][$collectionId])) { - return $this->collectionCache[$databoxId][$collectionId]; - } - - return null; - } - - private function getCollectionInCacheByBaseId($baseId) - { - if (isset($this->baseIdMap[$baseId])) { - list ($databoxId, $collectionId) = $this->baseIdMap[$baseId]; - - return $this->getCollectionInCache($databoxId, $collectionId); - } - - return null; - } - - private function getCollectionsInCache($databoxId) - { - if (isset($this->collectionCache[$databoxId])) { - return $this->collectionCache[$databoxId]; - } - - return []; - } - - /** - * @param int $databoxId - * @return \collection[] - */ - public function findAllByDatabox($databoxId) - { - if (! isset($this->databoxFlags[$databoxId]) || $this->databoxFlags[$databoxId] !== true) { - $this->putCollectionsInCache($this->collectionRepository->findAllByDatabox($databoxId)); - $this->databoxFlags[$databoxId] = true; - } - - return $this->getCollectionsInCache($databoxId); - } - - /** - * @param int $baseId - * @return \collection|null - */ - public function find($baseId) - { - if (! isset($this->baseIdMap[$baseId])) { - $this->putCollectionInCache($this->collectionRepository->find($baseId)); - } - - return $this->getCollectionInCacheByBaseId($baseId); - } - - /** - * @param int $databoxId - * @param int $collectionId - * @return \collection|null - */ - public function findByCollectionId($databoxId, $collectionId) - { - if (! isset($this->collectionCache[$databoxId][$collectionId])) { - $this->putCollectionInCache($this->collectionRepository->findByCollectionId($databoxId, $collectionId)); - } - - return $this->getCollectionInCache($databoxId, $collectionId); - } -} diff --git a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php index 18303e47df..482eb214ea 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php @@ -3,6 +3,7 @@ namespace Alchemy\Phrasea\Collection; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\Reference\CollectionReference; use Assert\Assertion; class CollectionFactory diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php index 5da5c4a492..2b5329bc52 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php @@ -6,21 +6,14 @@ interface CollectionRepository { /** - * @param int $databoxId * @return \collection[] */ - public function findAllByDatabox($databoxId); + public function findAll(); /** - * @param int $baseId - * @return \collection|null - */ - public function find($baseId); - - /** - * @param int $databoxId * @param int $collectionId * @return \collection|null */ - public function findByCollectionId($databoxId, $collectionId); + public function find($collectionId); + } diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepositoryFactory.php b/lib/Alchemy/Phrasea/Collection/CollectionRepositoryFactory.php new file mode 100644 index 0000000000..1fe2ca84e2 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepositoryFactory.php @@ -0,0 +1,12 @@ +repositoryFactory = $collectionRepositoryFactory; + $this->referenceRepository = $referenceRepository; + } + + /** + * @param $databoxId + * @return CollectionRepository + */ + public function getRepositoryByDatabox($databoxId) + { + if (!isset($this->repositories[$databoxId])) { + $this->repositories[$databoxId] = $this->repositoryFactory->createRepositoryForDatabox($databoxId); + } + + return $this->repositories[$databoxId]; + } + + /** + * @param int $baseId + * @return CollectionRepository + * @throws \OutOfBoundsException if no repository was found for the given baseId. + */ + public function getRepositoryByBase($baseId) + { + if ($this->baseIdMap === null) { + $this->loadBaseIdMap(); + } + + if (isset($this->baseIdMap[$baseId])) { + return $this->getRepositoryByDatabox($this->baseIdMap[$baseId]); + } + + throw new \OutOfBoundsException('No repository available for given base [baseId: ' . $baseId . ' ].'); + } + + private function loadBaseIdMap() + { + $references = $this->referenceRepository->findAll(); + + $this->baseIdMap = []; + + foreach ($references as $reference) { + $this->baseIdMap[$reference->getBaseId()] = $reference->getDataboxId(); + } + } +} diff --git a/lib/Alchemy/Phrasea/Collection/Factory/ArrayCachedCollectionRepositoryFactory.php b/lib/Alchemy/Phrasea/Collection/Factory/ArrayCachedCollectionRepositoryFactory.php new file mode 100644 index 0000000000..bec14d37e9 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/Factory/ArrayCachedCollectionRepositoryFactory.php @@ -0,0 +1,34 @@ +collectionRepositoryFactory = $collectionRepositoryFactory; + } + + /** + * @param int $databoxId + * @return CollectionRepository + */ + public function createRepositoryForDatabox($databoxId) + { + $repository = $this->collectionRepositoryFactory->createRepositoryForDatabox($databoxId); + + return new ArrayCacheCollectionRepository($repository); + } +} diff --git a/lib/Alchemy/Phrasea/Collection/Factory/CachedCollectionRepositoryFactory.php b/lib/Alchemy/Phrasea/Collection/Factory/CachedCollectionRepositoryFactory.php new file mode 100644 index 0000000000..601bd9671b --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/Factory/CachedCollectionRepositoryFactory.php @@ -0,0 +1,66 @@ +application = $application; + $this->collectionRepositoryFactory = $collectionRepositoryFactory; + $this->cache = $cache; + $this->baseCacheKey = (string)$baseCacheKey; + } + + /** + * @param int $databoxId + * @return CollectionRepository + */ + public function createRepositoryForDatabox($databoxId) + { + $repository = $this->collectionRepositoryFactory->createRepositoryForDatabox($databoxId); + + return new CachedCollectionRepository( + $this->application, + $repository, + $this->cache, + $this->baseCacheKey . '.' . $databoxId + ); + } +} diff --git a/lib/Alchemy/Phrasea/Collection/Factory/DbalCollectionRepositoryFactory.php b/lib/Alchemy/Phrasea/Collection/Factory/DbalCollectionRepositoryFactory.php new file mode 100644 index 0000000000..c26ea68872 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/Factory/DbalCollectionRepositoryFactory.php @@ -0,0 +1,60 @@ +databoxConnectionProvider = $connectionProvider; + $this->collectionFactory = $collectionFactory; + $this->collectionReferenceRepository = $referenceRepository; + } + + /** + * @param int $databoxId + * @return CollectionRepository + */ + public function createRepositoryForDatabox($databoxId) + { + $connection = $this->databoxConnectionProvider->getConnection($databoxId); + + return new DbalCollectionRepository( + $databoxId, + $connection, + $this->collectionReferenceRepository, + $this->collectionFactory + ); + } +} diff --git a/lib/Alchemy/Phrasea/Collection/CollectionReference.php b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php similarity index 97% rename from lib/Alchemy/Phrasea/Collection/CollectionReference.php rename to lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php index c5f51af7d4..55bf6f3234 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionReference.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php @@ -1,6 +1,6 @@ collectionRepository = $collectionRepository; + } + + /** + * @return \collection[] + */ + public function findAll() + { + if ($this->collectionCache === null) { + $this->collectionCache = $this->collectionRepository->findAll(); + } + + return $this->collectionCache; + } + + /** + * @param int $collectionId + * @return \collection|null + */ + public function find($collectionId) + { + $collections = $this->findAll(); + + if (isset($collections[$collectionId])) { + return $collections[$collectionId]; + } + + return null; + } +} diff --git a/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php similarity index 52% rename from lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php rename to lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php index 7dcf00aae4..7bac7f5c15 100644 --- a/lib/Alchemy/Phrasea/Collection/CachedCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php @@ -7,9 +7,10 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -namespace Alchemy\Phrasea\Collection; +namespace Alchemy\Phrasea\Collection\Repository; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\CollectionRepository; use Doctrine\Common\Cache\Cache; final class CachedCollectionRepository implements CollectionRepository @@ -50,17 +51,17 @@ final class CachedCollectionRepository implements CollectionRepository } /** - * @param int $databoxId * @return \collection[] */ - public function findAllByDatabox($databoxId) + public function findAll() { - $cacheKey = hash('sha256', $this->cacheKey . '.findAll.' . $databoxId); + $cacheKey = hash('sha256', $this->cacheKey . '.findAll'); + /** @var \collection[] $collections */ $collections = $this->cache->fetch($cacheKey); if ($collections === false) { - $collections = $this->repository->findAllByDatabox($databoxId); - $this->save($cacheKey, $collections); + $collections = $this->repository->findAll(); + $this->putInCache($cacheKey, $collections); } else { foreach ($collections as $collection) { $collection->hydrate($this->app); @@ -71,45 +72,21 @@ final class CachedCollectionRepository implements CollectionRepository } /** - * @param int $baseId - * @return \collection|null - */ - public function find($baseId) - { - $cacheKey = hash('sha256', $this->cacheKey . '.find.' . $baseId); - $collection = $this->cache->fetch($cacheKey); - - if ($collection === false) { - $collection = $this->repository->find($baseId); - $this->save($cacheKey, $collection); - } else { - $collection->hydrate($this->app); - } - - return $collection; - } - - /** - * @param int $databoxId * @param int $collectionId * @return \collection|null */ - public function findByCollectionId($databoxId, $collectionId) + public function find($collectionId) { - $cacheKey = hash('sha256', $this->cacheKey . '.findByCollection.' . $databoxId . $collectionId); - $collection = $this->cache->fetch($cacheKey); + $collections = $this->findAll(); - if ($collection === false) { - $collection = $this->repository->findByCollectionId($databoxId, $collectionId); - $this->save($cacheKey, $collection); - } else { - $collection->hydrate($this->app); + if (isset($collections[$collectionId])) { + return $collections[$collectionId]; } - return $collection; + return null; } - private function save($key, $value) + private function putInCache($key, $value) { $this->cache->save($key, $value); } diff --git a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php similarity index 63% rename from lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php rename to lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php index 203cf47bee..5274b6fb9f 100644 --- a/lib/Alchemy/Phrasea/Collection/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php @@ -1,8 +1,11 @@ connectionProvider = $connectionProvider; + $this->databoxId = (int) $databoxId; + $this->connection = $connection; $this->referenceRepository = $referenceRepository; $this->collectionFactory = $collectionFactory; } /** - * @param int $databoxId * @return \collection[] */ - public function findAllByDatabox($databoxId) + public function findAll() { - $references = $this->referenceRepository->findAllByDatabox($databoxId); - $connection = $this->connectionProvider->getConnection($databoxId); - + $references = $this->referenceRepository->findAllByDatabox($this->databoxId); $params = []; foreach ($references as $reference) { @@ -51,9 +58,9 @@ class DbalCollectionRepository implements CollectionRepository } $query = self::$query . sprintf(' WHERE coll_id IN (%s)', implode(', ', array_keys($params))); - $rows = $connection->fetchAll($query, $params); + $rows = $this->connection->fetchAll($query, $params); - return $this->collectionFactory->createMany($databoxId, $references, $rows); + return $this->collectionFactory->createMany($this->databoxId, $references, $rows); } /** @@ -68,13 +75,11 @@ class DbalCollectionRepository implements CollectionRepository return null; } - $connection = $this->connectionProvider->getConnection($reference->getDataboxId()); - $query = self::$query . ' WHERE coll_id = :collectionId'; - $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); + $row = $this->connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { - return $this->collectionFactory->create($reference->getDataboxId(), $reference, $row); + return $this->collectionFactory->create($this->databoxId, $reference, $row); } return null; @@ -93,13 +98,11 @@ class DbalCollectionRepository implements CollectionRepository return null; } - $connection = $this->connectionProvider->getConnection($databoxId); - $query = self::$query . ' WHERE coll_id = :collectionId'; - $row = $connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); + $row = $this->connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { - return $this->collectionFactory->create($databoxId, $reference, $row); + return $this->collectionFactory->create($this->databoxId, $reference, $row); } return null; diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index fc7bb084c3..58bc0839a1 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -12,11 +12,15 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Application as PhraseaApplication; -use Alchemy\Phrasea\Collection\ArrayCacheCollectionRepository; use Alchemy\Phrasea\Collection\CollectionFactory; -use Alchemy\Phrasea\Collection\DbalCollectionReferenceRepository; -use Alchemy\Phrasea\Collection\DbalCollectionRepository; -use Alchemy\Phrasea\Collection\CachedCollectionRepository; +use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; +use Alchemy\Phrasea\Collection\Factory\ArrayCachedCollectionRepositoryFactory; +use Alchemy\Phrasea\Collection\Factory\CachedCollectionRepositoryFactory; +use Alchemy\Phrasea\Collection\Factory\DbalCollectionRepositoryFactory; +use Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository; +use Alchemy\Phrasea\Collection\Repository\ArrayCacheCollectionRepository; +use Alchemy\Phrasea\Collection\Repository\CachedCollectionRepository; +use Alchemy\Phrasea\Collection\Repository\DbalCollectionRepository; use Alchemy\Phrasea\Databox\CachingDataboxRepositoryDecorator; use Alchemy\Phrasea\Databox\DataboxConnectionProvider; use Alchemy\Phrasea\Databox\DataboxFactory; @@ -149,19 +153,26 @@ class RepositoriesServiceProvider implements ServiceProviderInterface return new DbalCollectionReferenceRepository($app->getApplicationBox()->get_connection()); }); - $app['repo.collections'] = $app->share(function (PhraseaApplication $app) { - $appbox = $app->getApplicationBox(); + $app['repo.collections-registry'] = $app->share(function (PhraseaApplication $app) { $factory = new CollectionFactory($app); - $connectionProvider = new DataboxConnectionProvider($appbox); - $repository = new DbalCollectionRepository( + $connectionProvider = new DataboxConnectionProvider($app->getApplicationBox()); + + $repositoryFactory = new DbalCollectionRepositoryFactory( $connectionProvider, - $app['repo.collection-references'], - $factory + $factory, + $app['repo.collection-references'] ); - $repository = new CachedCollectionRepository($app, $repository, $app['cache'], 'collection_'); + $repositoryFactory = new CachedCollectionRepositoryFactory( + $app, + $repositoryFactory, + $app['cache'], + 'phrasea.collections' + ); - return new ArrayCacheCollectionRepository($repository); + $repositoryFactory = new ArrayCachedCollectionRepositoryFactory($repositoryFactory); + + return new CollectionRepositoryRegistry($repositoryFactory, $app['repo.collection-references']); }); } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 18ee44a755..1eb751db10 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -10,8 +10,9 @@ */ use Alchemy\Phrasea\Application; -use Alchemy\Phrasea\Collection\CollectionReference; -use Alchemy\Phrasea\Collection\CollectionRepository; +use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; +use Alchemy\Phrasea\Collection\Reference\CollectionReference; +use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository; use Alchemy\Phrasea\Core\Event\Collection\CollectionEvent; use Alchemy\Phrasea\Core\Event\Collection\CollectionEvents; use Alchemy\Phrasea\Core\Event\Collection\CreatedEvent; @@ -196,9 +197,18 @@ EOT; */ public static function getByBaseId(Application $app, $base_id) { - /** @var CollectionRepository $repository */ - $repository = $app['repo.collections']; - $collection = $repository->find($base_id); + /** @var CollectionReferenceRepository $referenceRepository */ + $referenceRepository = $app['repo.collection-references']; + $reference = $referenceRepository->find($base_id); + + if (! $reference) { + throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); + } + + /** @var CollectionRepositoryRegistry $registry */ + $registry = $app['repo.collections-registry']; + $repository = $registry->getRepositoryByDatabox($reference->getDataboxId()); + $collection = $repository->find($reference->getCollectionId()); if (! $collection) { throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); @@ -221,16 +231,23 @@ EOT; { assert(is_int($coll_id)); - /** @var CollectionRepository $repository */ - $repository = $app['repo.collections']; - $collection = $repository->findByCollectionId($databox->get_sbas_id(), $coll_id); + /** @var CollectionRepositoryRegistry $registry */ + $registry = $app['repo.collections-registry']; + $repository = $registry->getRepositoryByDatabox($databox->get_sbas_id()); + $collection = $repository->find($coll_id); - if (! $collection) { - throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_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('Collection `' . $collection->get_base_id() . '` is not available here.'); + throw new Exception_Databox_CollectionNotFound(sprintf( + 'Collection `%d` is not available here.', + $collection->get_base_id()) + ); } return $collection; @@ -344,6 +361,7 @@ EOT; $this->delete_data_from_cache(); $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); $this->databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); + cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); return $this; diff --git a/lib/classes/databox.php b/lib/classes/databox.php index 485e8f21d1..784c536a08 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -10,7 +10,7 @@ */ use Alchemy\Phrasea\Application; -use Alchemy\Phrasea\Collection\CollectionRepository; +use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; use Alchemy\Phrasea\Core\Connection\ConnectionSettings; use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Core\Version\DataboxVersionRepository; @@ -155,14 +155,19 @@ class databox extends base implements \Alchemy\Phrasea\Core\Thumbnail\Thumbnaile static $collections; if ($collections === null) { - /** @var CollectionRepository $collectionsRepository */ - $collectionsRepository = $this->app['repo.collections']; - $collections = $collectionsRepository->findAllByDatabox($this->get_sbas_id()); + /** @var CollectionRepositoryRegistry $repositoryRegistry */ + $repositoryRegistry = $this->app['repo.collections-registry']; + $repository = $repositoryRegistry->getRepositoryByDatabox($this->get_sbas_id()); + + $collections = $repository->findAll(); } return $collections; } + /** + * @return int[] + */ public function get_collection_unique_ids() { static $collectionsIds; From c5cab178a9be9433b5ebabacc28c8738cbe621d8 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 19:00:34 +0200 Subject: [PATCH 10/17] Add cache busting via save method of collection repository --- .../Collection/CollectionRepository.php | 5 ++ .../ArrayCacheCollectionRepository.php | 9 ++++ .../Repository/CachedCollectionRepository.php | 11 ++++- .../Repository/DbalCollectionRepository.php | 5 ++ lib/classes/collection.php | 47 ++++++++++++++----- 5 files changed, 63 insertions(+), 14 deletions(-) diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php index 2b5329bc52..1f267a4c50 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php @@ -16,4 +16,9 @@ interface CollectionRepository */ public function find($collectionId); + /** + * @param \collection $collection + * @return void + */ + public function save(\collection $collection); } diff --git a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php index 96e5aef66a..02d62740b1 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php @@ -47,4 +47,13 @@ class ArrayCacheCollectionRepository implements CollectionRepository return null; } + + public function save(\collection $collection) + { + $this->collectionRepository->save($collection); + + if ($this->collectionCache !== null) { + $this->collectionCache[$collection->get_coll_id()] = $collection; + } + } } diff --git a/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php index 7bac7f5c15..796e6684e5 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php @@ -55,7 +55,7 @@ final class CachedCollectionRepository implements CollectionRepository */ public function findAll() { - $cacheKey = hash('sha256', $this->cacheKey . '.findAll'); + $cacheKey = hash('sha256', $this->cacheKey); /** @var \collection[] $collections */ $collections = $this->cache->fetch($cacheKey); @@ -86,6 +86,15 @@ final class CachedCollectionRepository implements CollectionRepository return null; } + public function save(\collection $collection) + { + $this->repository->save($collection); + + $cacheKey = hash('sha256', $this->cacheKey); + + $this->cache->delete($cacheKey); + } + private function putInCache($key, $value) { $this->cache->save($key, $value); diff --git a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php index 5274b6fb9f..3a55b9554d 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php @@ -107,4 +107,9 @@ class DbalCollectionRepository implements CollectionRepository return null; } + + public function save(\collection $collection) + { + + } } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 1eb751db10..fd518d8dd4 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\CollectionRepository; use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; use Alchemy\Phrasea\Collection\Reference\CollectionReference; use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository; @@ -49,6 +50,19 @@ class collection implements cache_cacheableInterface, ThumbnailedElement return $ord['ord'] ?: 1; } + /** + * @param Application $app + * @param $databoxId + * @return CollectionRepository + */ + private static function getRepository(Application $app, $databoxId) + { + /** @var CollectionRepositoryRegistry $registry */ + $registry = $app['repo.collections-registry']; + + return $registry->getRepositoryByDatabox($databoxId); + } + public static function create(Application $app, databox $databox, appbox $appbox, $name, User $user = null) { $sbas_id = $databox->get_sbas_id(); @@ -201,21 +215,28 @@ EOT; $referenceRepository = $app['repo.collection-references']; $reference = $referenceRepository->find($base_id); - if (! $reference) { - throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); + if (!$reference) { + throw new Exception_Databox_CollectionNotFound(sprintf( + "Collection with base_id %s could not be found", + $base_id + )); } - /** @var CollectionRepositoryRegistry $registry */ - $registry = $app['repo.collections-registry']; - $repository = $registry->getRepositoryByDatabox($reference->getDataboxId()); + $repository = self::getRepository($app, $reference->getDataboxId()); $collection = $repository->find($reference->getCollectionId()); - if (! $collection) { - throw new Exception_Databox_CollectionNotFound(sprintf("Collection with base_id %s could not be found", $base_id)); + if (!$collection) { + throw new Exception_Databox_CollectionNotFound(sprintf( + "Collection with base_id %s could not be found", + $base_id + )); } if (!$app['conf.restrictions']->isCollectionAvailable($collection)) { - throw new Exception_Databox_CollectionNotFound('Collection `' . $collection->get_base_id() . '` is not available here.'); + throw new Exception_Databox_CollectionNotFound(sprintf( + 'Collection `%d` is not available here.', + $collection->get_base_id() + )); } return $collection; @@ -231,9 +252,7 @@ EOT; { assert(is_int($coll_id)); - /** @var CollectionRepositoryRegistry $registry */ - $registry = $app['repo.collections-registry']; - $repository = $registry->getRepositoryByDatabox($databox->get_sbas_id()); + $repository = self::getRepository($app, $databox->get_sbas_id()); $collection = $repository->find($coll_id); if (!$collection) { @@ -246,8 +265,8 @@ EOT; if (!$app['conf.restrictions']->isCollectionAvailable($collection)) { throw new Exception_Databox_CollectionNotFound(sprintf( 'Collection `%d` is not available here.', - $collection->get_base_id()) - ); + $collection->get_base_id() + )); } return $collection; @@ -814,6 +833,8 @@ EOT; public function delete_data_from_cache($option = null) { + self::getRepository($this->app, $this->reference->getDataboxId())->save($this); + return $this->databox->delete_data_from_cache($this->get_cache_key($option)); } From 07c0691092f1c32faac178227db232f2d89c2bd1 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 9 Jul 2015 20:13:46 +0200 Subject: [PATCH 11/17] Implement save method in collection reference repository --- .../Reference/CollectionReference.php | 12 ++++ .../CollectionReferenceRepository.php | 6 ++ .../DbalCollectionReferenceRepository.php | 59 +++++++++++++++++-- .../Controller/Admin/DataboxController.php | 2 +- lib/classes/collection.php | 15 ++--- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php index 55bf6f3234..5f0f74b3c8 100644 --- a/lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReference.php @@ -68,6 +68,18 @@ class CollectionReference return $this->baseId; } + /** + * @param int $baseId + */ + public function setBaseId($baseId) + { + if ($this->baseId > 0) { + throw new \LogicException('Cannot change the baseId of an existing collection reference.'); + } + + $this->baseId = $baseId; + } + /** * @return int */ diff --git a/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php index f9ea3e61dd..b90b02e1de 100644 --- a/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php @@ -27,4 +27,10 @@ interface CollectionReferenceRepository * @return CollectionReference|null */ public function findByCollectionId($databoxId, $collectionId); + + /** + * @param CollectionReference $reference + * @return void + */ + public function save(CollectionReference $reference); } diff --git a/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php index 9694636999..070186dc5c 100644 --- a/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php @@ -2,15 +2,35 @@ namespace Alchemy\Phrasea\Collection\Reference; +use Alchemy\Phrasea\Core\Database\QueryBuilder; use Doctrine\DBAL\Connection; class DbalCollectionReferenceRepository implements CollectionReferenceRepository { - private static $query = 'SELECT base_id AS baseId, sbas_id AS databoxId, server_coll_id AS collectionId, + private static $table = 'bas'; + + private static $columns = [ + 'base_id' => 'baseId', + 'sbas_id' => 'databoxId', + 'server_coll_id' => 'collectionId', + 'ord' => 'displayIndex', + 'active' => 'isActive', + 'aliases' => 'alias' + ]; + + private static $selectQuery = 'SELECT base_id AS baseId, sbas_id AS databoxId, server_coll_id AS collectionId, ord AS displayIndex, active AS isActive, aliases AS alias FROM bas'; + private static $insertQuery = 'INSERT INTO bas (sbas_id, server_coll_id, ord, active, aliases) + VALUES (:databoxId, :collectionId, + (SELECT COALESCE(MAX(ord), 0) + 1 AS ord FROM bas WHERE sbas_id = :sbas_id), + :isActive, :alias)'; + + private static $updateQuery = 'UPDATE bas SET ord = :displayIndex, active = :isActive, aliases = :alias + WHERE base_id = :baseId'; + /** * @var Connection */ @@ -29,7 +49,7 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository */ public function findAll() { - return $this->createManyReferences($this->connection->fetchAll(self::$query)); + return $this->createManyReferences($this->connection->fetchAll(self::$selectQuery)); } /** @@ -38,7 +58,7 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository */ public function findAllByDatabox($databoxId) { - $query = self::$query . ' WHERE sbas_id = :databoxId'; + $query = self::$selectQuery . ' WHERE sbas_id = :databoxId'; $rows = $this->connection->fetchAll($query, [ ':databoxId' => $databoxId ]); return $this->createManyReferences($rows); @@ -50,7 +70,7 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository */ public function find($baseId) { - $query = self::$query . ' WHERE base_id = :baseId'; + $query = self::$selectQuery . ' WHERE base_id = :baseId'; $row = $this->connection->fetchAssoc($query, [ ':baseId' => $baseId ]); if ($row !== false) { @@ -67,7 +87,7 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository */ public function findByCollectionId($databoxId, $collectionId) { - $query = self::$query . ' WHERE sbas_id = :databoxId AND server_coll_id = :collectionId'; + $query = self::$selectQuery . ' WHERE sbas_id = :databoxId AND server_coll_id = :collectionId'; $row = $this->connection->fetchAssoc($query, [ ':databoxId' => $databoxId, ':collectionId' => $collectionId ]); if ($row !== false) { @@ -77,6 +97,35 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository return null; } + public function save(CollectionReference $collectionReference) + { + $query = self::$insertQuery; + $isInsert = true; + + $parameters = [ + 'isActive' => $collectionReference->isActive(), + 'alias' => $collectionReference->getAlias() + ]; + + if ($collectionReference->getBaseId() > 0) { + $query = self::$updateQuery; + $isInsert = false; + + $parameters['baseId'] = $collectionReference->getBaseId(); + $parameters['displayIndex'] = $collectionReference->getDisplayIndex(); + } + else { + $parameters['databoxId'] = $collectionReference->getDataboxId(); + $parameters['collectionId'] = $collectionReference->getCollectionId(); + } + + $this->connection->executeQuery($query, $parameters); + + if ($isInsert) { + $collectionReference->setBaseId($this->connection->lastInsertId()); + } + } + /** * @param array $row * @return CollectionReference diff --git a/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php b/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php index 21dd1a9bf0..5825ef22bc 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/DataboxController.php @@ -718,7 +718,7 @@ class DataboxController extends Controller } catch (\Exception $e) { return $this->app->redirectPath('admin_database_submit_collection', [ 'databox_id' => $databox_id, - 'error' => 'error', + 'error' => $e->getMessage(), ]); } } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index fd518d8dd4..efdfeb172a 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -92,18 +92,11 @@ EOT; $new_id = (int) $connbas->lastInsertId(); - $sql = "INSERT INTO bas (base_id, active, ord, server_coll_id, sbas_id, aliases) - VALUES - (null, 1, :ord, :server_coll_id, :sbas_id, '')"; - $stmt = $conn->prepare($sql); - $stmt->execute([ - ':server_coll_id' => $new_id, - ':sbas_id' => $sbas_id, - ':ord' => self::getNewOrder($conn, $sbas_id), - ]); - $stmt->closeCursor(); + $repository = $app['repo.collection-references']; + $collectionReference = new CollectionReference(0, $sbas_id, $new_id, 0, true, ''); + + $repository->save($collectionReference); - $new_bas = $conn->lastInsertId(); $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); From 616f57e8edfc57a561a46765e5a798418893666f Mon Sep 17 00:00:00 2001 From: Aztech Date: Fri, 10 Jul 2015 10:09:35 +0200 Subject: [PATCH 12/17] WIP Extract collection service --- lib/Alchemy/Phrasea/Collection/Collection.php | 229 +++++ .../Collection/CollectionRepository.php | 4 +- .../Phrasea/Collection/CollectionService.php | 270 ++++++ .../ArrayCacheCollectionRepository.php | 3 +- .../Repository/CachedCollectionRepository.php | 3 +- .../Repository/DbalCollectionRepository.php | 9 +- lib/classes/collection.php | 779 +++++++----------- 7 files changed, 829 insertions(+), 468 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Collection/Collection.php create mode 100644 lib/Alchemy/Phrasea/Collection/CollectionService.php diff --git a/lib/Alchemy/Phrasea/Collection/Collection.php b/lib/Alchemy/Phrasea/Collection/Collection.php new file mode 100644 index 0000000000..b7e0d3f490 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/Collection.php @@ -0,0 +1,229 @@ +databoxId = (int) $databoxId; + $this->collectionId = (int) $collectionId; + $this->name = (string) $name; + $this->preferences = << + + 0 + + +EOT; + } + + /** + * @return int + */ + public function getDataboxId() + { + return $this->databoxId; + } + + /** + * @return int + */ + public function getCollectionId() + { + return $this->collectionId; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $name = trim(strip_tags($name)); + + if ($name === '') { + throw new \InvalidArgumentException(); + } + + $this->name = $name; + } + + /** + * @return \string[] + */ + public function getLabels() + { + return $this->labels; + } + + /** + * @param \string[] $labels + */ + public function setLabels($labels) + { + $this->labels = $labels; + } + + /** + * @param $lang + * @param bool $substitute + * @return string + */ + public function getLabel($lang, $substitute = true) + { + if (!array_key_exists($lang, $this->labels)) { + throw new \InvalidArgumentException(sprintf('Code %s is not defined', $lang)); + } + + if ($substitute) { + return isset($this->labels[$lang]) ? $this->labels[$lang] : $this->name; + } else { + return $this->labels[$lang]; + } + } + + /** + * @param $lang + * @param $label + */ + public function setLabel($lang, $label) + { + if (!array_key_exists($lang, $this->labels)) { + throw new \InvalidArgumentException(sprintf("Language '%s' is not defined.", $lang)); + } + + $this->labels[$lang] = $label; + } + + /** + * @return \int[]|string|null + */ + public function getLogo() + { + return $this->logo; + } + + /** + * @param \int[]|string $logo + */ + public function setLogo($logo) + { + $this->logo = $logo; + } + + /** + * @return \DateTimeInterface + */ + public function getLogoUpdatedAt() + { + return $this->logoUpdatedAt; + } + + /** + * @return string + */ + public function getPublicWatermark() + { + return $this->publicWatermark; + } + + /** + * @param string $publicWatermark + */ + public function setPublicWatermark($publicWatermark) + { + if (! in_array($publicWatermark, ['none', 'wm', 'stamp'])) { + return; + } + + $this->publicWatermark = $publicWatermark; + } + + /** + * @return string + */ + public function getPreferences() + { + return $this->preferences; + } + + /** + * @param string $preferences + */ + public function setPreferences($preferences) + { + $this->preferences = $preferences; + } + + /** + * @return CollectionReference + */ + public function getCollectionReference() + { + return $this->collectionReference; + } + + /** + * @param CollectionReference $collectionReference + */ + public function setCollectionReference($collectionReference) + { + $this->collectionReference = $collectionReference; + } +} diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php index 1f267a4c50..aadf24148c 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php @@ -17,8 +17,8 @@ interface CollectionRepository public function find($collectionId); /** - * @param \collection $collection + * @param Collection $collection * @return void */ - public function save(\collection $collection); + public function save(Collection $collection); } diff --git a/lib/Alchemy/Phrasea/Collection/CollectionService.php b/lib/Alchemy/Phrasea/Collection/CollectionService.php new file mode 100644 index 0000000000..3707aa0157 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/CollectionService.php @@ -0,0 +1,270 @@ +app = $application; + $this->connection = $connection; + $this->connectionProvider = $connectionProvider; + } + + /** + * @param Collection $collection + * @return int|null + * @throws \Doctrine\DBAL\DBALException + */ + public function getRecordCount(Collection $collection) + { + $connection = $this->connectionProvider->getConnection($collection->getDataboxId()); + + $sql = "SELECT COALESCE(COUNT(record_id), 0) AS recordCount FROM record WHERE coll_id = :coll_id"; + $stmt = $connection->prepare($sql); + $stmt->execute([':coll_id' => $collection->getCollectionId()]); + $rowbas = $stmt->fetch(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + + $amount = $rowbas ? (int) $rowbas["recordCount"] : null; + + return $amount; + } + + /** + * @param Collection $collection + * @return array + */ + public function getRecordDetails(Collection $collection) + { + $sql = "SELECT record.coll_id,name,COALESCE(asciiname, CONCAT('_',record.coll_id)) AS asciiname, + SUM(1) AS n, SUM(size) AS size + FROM record NATURAL JOIN subdef + INNER JOIN coll ON record.coll_id=coll.coll_id AND coll.coll_id = :coll_id + GROUP BY record.coll_id, subdef.name"; + + $connection = $this->connectionProvider->getConnection($collection->getDataboxId()); + + $stmt = $connection->prepare($sql); + $stmt->execute([':coll_id' => $collection->getCollectionId()]); + $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + + $ret = []; + foreach ($rs as $row) { + $ret[] = [ + "coll_id" => (int) $row["coll_id"], + "name" => $row["name"], + "amount" => (int) $row["n"], + "size" => (int) $row["size"]]; + } + + return $ret; + } + + /** + * @param Collection $collection + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ + public function resetWatermark(Collection $collection) + { + $sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id) + WHERE r.coll_id = :coll_id AND r.type="image" AND s.name="preview"'; + + $connection = $this->connectionProvider->getConnection($collection->getDataboxId()); + + $stmt = $connection->prepare($sql); + $stmt->execute([':coll_id' => $collection->getCollectionId()]); + + while ($row2 = $stmt->fetch(\PDO::FETCH_ASSOC)) { + @unlink(\p4string::addEndSlash($row2['path']) . 'watermark_' . $row2['file']); + } + $stmt->closeCursor(); + + return $this; + } + + /** + * @param Collection $collection + * @param int|null $record_id + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ + public function resetStamp(Collection $collection, $record_id = null) + { + $sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id) + WHERE r.coll_id = :coll_id + AND r.type="image" AND s.name IN ("preview", "document")'; + + + $params = [':coll_id' => $collection->getCollectionId()]; + + if ($record_id) { + $sql .= ' AND record_id = :record_id'; + $params[':record_id'] = $record_id; + } + + $connection = $this->connectionProvider->getConnection($collection->getDataboxId()); + + $stmt = $connection->prepare($sql); + $stmt->execute($params); + + while ($row2 = $stmt->fetch(\PDO::FETCH_ASSOC)) { + @unlink(\p4string::addEndSlash($row2['path']) . 'stamp_' . $row2['file']); + } + $stmt->closeCursor(); + + return $this; + } + + /** + * @param \databox $databox + * @param Collection $collection + * @param CollectionReference $reference + * @throws \Doctrine\DBAL\DBALException + */ + public function delete(\databox $databox, Collection $collection, CollectionReference $reference) + { + while ($this->getRecordCount($collection) > 0) { + $this->emptyCollection($databox, $collection); + } + + $connection = $this->connectionProvider->getConnection($collection->getDataboxId()); + + $sql = "DELETE FROM coll WHERE coll_id = :coll_id"; + $stmt = $connection->prepare($sql); + $stmt->execute([':coll_id' => $collection->getCollectionId()]); + $stmt->closeCursor(); + + $sql = "DELETE FROM bas WHERE base_id = :base_id"; + $stmt = $this->connection->prepare($sql); + $stmt->execute([':base_id' => $reference->getBaseId()]); + $stmt->closeCursor(); + + $sql = "DELETE FROM basusr WHERE base_id = :base_id"; + $stmt = $this->connection->prepare($sql); + $stmt->execute([':base_id' => $reference->getBaseId()]); + $stmt->closeCursor(); + + $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); + + return; + } + + /** + * @param \databox $databox + * @param Collection $collection + * @param int $pass_quantity + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ + public function emptyCollection(\databox $databox, Collection $collection, $pass_quantity = 100) + { + $pass_quantity = (int) $pass_quantity > 200 ? 200 : (int) $pass_quantity; + $pass_quantity = (int) $pass_quantity < 10 ? 10 : (int) $pass_quantity; + + $sql = "SELECT record_id FROM record WHERE coll_id = :coll_id + ORDER BY record_id DESC LIMIT 0, " . $pass_quantity; + + $connection = $this->connectionProvider->getConnection($collection->getDataboxId()); + + $stmt = $connection->prepare($sql); + $stmt->execute([':coll_id' => $collection->getCollectionId()]); + $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + + foreach ($rs as $row) { + $record = $databox->get_record($row['record_id']); + $record->delete(); + unset($record); + } + + return $this; + } + + /** + * @param CollectionReference $reference + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ + public function unmountCollection(CollectionReference $reference) + { + $params = [':base_id' => $reference->getBaseId()]; + + $query = $this->app['phraseanet.user-query']; + $total = $query->on_base_ids([$reference->getBaseId()]) + ->include_phantoms(false) + ->include_special_users(true) + ->include_invite(true) + ->include_templates(true)->get_total(); + $n = 0; + + while ($n < $total) { + $results = $query->limit($n, 50)->execute()->get_results(); + + foreach ($results as $user) { + $this->app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_SBAS); + $this->app->getAclForUser($user)->delete_data_from_cache(\ACL::CACHE_RIGHTS_BAS); + } + + $n+=50; + } + + $sql = "DELETE FROM basusr WHERE base_id = :base_id"; + $stmt = $this->connection->prepare($sql); + $stmt->execute($params); + $stmt->closeCursor(); + + $sql = "DELETE FROM bas WHERE base_id = :base_id"; + $stmt = $this->connection->prepare($sql); + $stmt->execute($params); + $stmt->closeCursor(); + + $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); + } + + /** + * @param CollectionReference $reference + * @param User $user + */ + public function grantAdminRights(CollectionReference $reference, User $user) + { + $rights = [ + "canputinalbum" => "1", + "candwnldhd" => "1", + "nowatermark" => "1", + "candwnldpreview" => "1", + "cancmd" => "1", + "canadmin" => "1", + "actif" => "1", + "canreport" => "1", + "canpush" => "1", + "basusr_infousr" => "", + "canaddrecord" => "1", + "canmodifrecord" => "1", + "candeleterecord" => "1", + "chgstatus" => "1", + "imgtools" => "1", + "manage" => "1", + "modify_struct" => "1" + ]; + + $this->app->getAclForUser($user)->update_rights_to_base($reference->getBaseId(), $rights); + } +} diff --git a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php index 02d62740b1..2902841f6b 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php @@ -2,6 +2,7 @@ namespace Alchemy\Phrasea\Collection\Repository; +use Alchemy\Phrasea\Collection\Collection; use Alchemy\Phrasea\Collection\CollectionRepository; class ArrayCacheCollectionRepository implements CollectionRepository @@ -48,7 +49,7 @@ class ArrayCacheCollectionRepository implements CollectionRepository return null; } - public function save(\collection $collection) + public function save(Collection $collection) { $this->collectionRepository->save($collection); diff --git a/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php index 796e6684e5..5dd84f7c53 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php @@ -10,6 +10,7 @@ namespace Alchemy\Phrasea\Collection\Repository; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\Collection; use Alchemy\Phrasea\Collection\CollectionRepository; use Doctrine\Common\Cache\Cache; @@ -86,7 +87,7 @@ final class CachedCollectionRepository implements CollectionRepository return null; } - public function save(\collection $collection) + public function save(Collection $collection) { $this->repository->save($collection); diff --git a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php index 3a55b9554d..b261f6f78e 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php @@ -2,6 +2,7 @@ namespace Alchemy\Phrasea\Collection\Repository; +use Alchemy\Phrasea\Collection\Collection; use Alchemy\Phrasea\Collection\CollectionFactory; use Alchemy\Phrasea\Collection\CollectionRepository; use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository; @@ -33,6 +34,12 @@ class DbalCollectionRepository implements CollectionRepository */ private $collectionFactory; + /** + * @param $databoxId + * @param Connection $connection + * @param CollectionReferenceRepository $referenceRepository + * @param CollectionFactory $collectionFactory + */ public function __construct( $databoxId, Connection $connection, @@ -108,7 +115,7 @@ class DbalCollectionRepository implements CollectionRepository return null; } - public function save(\collection $collection) + public function save(Collection $collection) { } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index efdfeb172a..b1e2c0ac28 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -10,8 +10,10 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\Collection as CollectionVO; use Alchemy\Phrasea\Collection\CollectionRepository; use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; +use Alchemy\Phrasea\Collection\CollectionService; use Alchemy\Phrasea\Collection\Reference\CollectionReference; use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository; use Alchemy\Phrasea\Core\Event\Collection\CollectionEvent; @@ -20,9 +22,7 @@ use Alchemy\Phrasea\Core\Event\Collection\CreatedEvent; use Alchemy\Phrasea\Core\Event\Collection\NameChangedEvent; use Alchemy\Phrasea\Core\Thumbnail\ThumbnailedElement; use Alchemy\Phrasea\Core\Thumbnail\ThumbnailManager; -use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Model\Entities\User; -use Doctrine\DBAL\Driver\Connection; use Symfony\Component\HttpFoundation\File\File; class collection implements cache_cacheableInterface, ThumbnailedElement @@ -39,17 +39,6 @@ class collection implements cache_cacheableInterface, ThumbnailedElement private static $_presentations = []; private static $_collections = []; - private static function getNewOrder(Connection $conn, $sbas_id) - { - $sql = "SELECT GREATEST(0, MAX(ord)) + 1 AS ord FROM bas WHERE sbas_id = :sbas_id"; - $stmt = $conn->prepare($sql); - $stmt->execute([':sbas_id' => $sbas_id]); - $ord = $stmt->fetch(\PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - return $ord['ord'] ?: 1; - } - /** * @param Application $app * @param $databoxId @@ -65,35 +54,15 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public static function create(Application $app, databox $databox, appbox $appbox, $name, User $user = null) { - $sbas_id = $databox->get_sbas_id(); - $connbas = $databox->get_connection(); - $conn = $appbox->get_connection(); - $new_bas = false; + $databoxId = $databox->get_sbas_id(); - $prefs = << - - 0 - - -EOT; + $repository = self::getRepository($app, $databoxId); + $collection = new CollectionVO($databoxId, 0, $name); - $sql = "INSERT INTO coll (coll_id, asciiname, prefs, logo) - VALUES (null, :name, :prefs, '')"; - - $params = [ - ':name' => $name, - 'prefs' => $prefs, - ]; - - $stmt = $connbas->prepare($sql); - $stmt->execute($params); - $stmt->closeCursor(); - - $new_id = (int) $connbas->lastInsertId(); + $repository->save($collection); $repository = $app['repo.collection-references']; - $collectionReference = new CollectionReference(0, $sbas_id, $new_id, 0, true, ''); + $collectionReference = new CollectionReference(0, $databoxId, $collection->getCollectionId(), 0, true, ''); $repository->save($collectionReference); @@ -102,10 +71,8 @@ EOT; phrasea::reset_baseDatas($appbox); - $collection = self::getByCollectionId($app, $databox, $new_id); - if (null !== $user) { - $collection->set_admin($new_bas, $user); + $collection->set_admin($collectionReference->getBaseId(), $user); } $app['dispatcher']->dispatch(CollectionEvents::CREATED, new CreatedEvent($collection)); @@ -115,30 +82,21 @@ EOT; public static function mount_collection(Application $app, databox $databox, $coll_id, User $user) { - $sql = "INSERT INTO bas (base_id, active, server_coll_id, sbas_id, aliases, ord) - VALUES - (null, 1, :server_coll_id, :sbas_id, '', :ord)"; - $stmt = $databox->get_appbox()->get_connection()->prepare($sql); - $stmt->execute([ - ':server_coll_id' => $coll_id, - ':sbas_id' => $databox->get_sbas_id(), - ':ord' => self::getNewOrder($databox->get_appbox()->get_connection(), $databox->get_sbas_id()), - ]); - $stmt->closeCursor(); + $reference = new CollectionReference(0, $databox->get_sbas_id(), $coll_id, 0, true, ''); + + $app['repo.collection-references']->save($reference); - $new_bas = $databox->get_appbox()->get_connection()->lastInsertId(); $databox->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); - $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); cache_databox::update($app, $databox->get_sbas_id(), 'structure'); phrasea::reset_baseDatas($databox->get_appbox()); - $coll = self::getByBaseId($app, $new_bas); - $coll->set_admin($new_bas, $user); + $coll = self::getByBaseId($app, $reference->getBaseId()); + $coll->set_admin($reference->getBaseId(), $user); - return $new_bas; + return $reference->getBaseId(); } public static function getLogo($base_id, Application $app, $printname = false) @@ -270,76 +228,66 @@ EOT; */ protected $app; + /** + * @var CollectionService + */ + protected $collectionService; + /** * @var databox */ protected $databox; + /** + * @var CollectionVO + */ + protected $collectionVO; + /** * @var CollectionReference */ protected $reference; - /** - * @var string - */ - protected $name; - - /** - * @var string - */ - protected $preferences; - - /** - * @var string - */ - protected $pub_wm; - - /** - * @var string[] - */ - protected $labels = []; - - /** - * @var int[]|string - */ - protected $binary_logo; /** * @param Application $app - * @param $baseId + * @param CollectionVO $collection * @param CollectionReference $reference - * @param array $row + * @internal param $baseId + * @internal param array $row */ - public function __construct(Application $app, $baseId, CollectionReference $reference, array $row) + public function __construct(Application $app, CollectionVO $collection, CollectionReference $reference) { $this->app = $app; $this->databox = $app->getApplicationBox()->get_databox($reference->getDataboxId()); + $this->collection = $collection; $this->reference = $reference; - - $this->name = $row['asciiname']; - $this->available = true; - $this->pub_wm = $row['pub_wm']; - $this->preferences = $row['prefs']; - $this->labels = [ - 'fr' => $row['label_fr'], - 'en' => $row['label_en'], - 'de' => $row['label_de'], - 'nl' => $row['label_nl'], - ]; } - public function __sleep() + /** + * @param $eventName + * @param CollectionEvent $event + */ + private function dispatch($eventName, CollectionEvent $event) { - return array( - 'reference', - 'name', - 'preferences', - 'pub_wm', - 'labels', - 'binary_logo' - ); + $this->app['dispatcher']->dispatch($eventName, $event); + } + + /** + * @return CollectionRepository + */ + private function getCollectionRepository() + { + return self::getRepository($this->app, $this->reference->getDataboxId()); + } + + /** + * @return CollectionReferenceRepository + */ + private function getReferenceRepository() + { + return $this->app['repo.collection-references']; } public function hydrate(Application $app) @@ -348,6 +296,14 @@ EOT; $this->databox = $app->getApplicationBox()->get_databox($this->reference->getDataboxId()); } + public function __sleep() + { + return array( + 'collection', + 'reference' + ); + } + /** * @return CollectionReference */ @@ -356,84 +312,6 @@ EOT; return $this->reference; } - private function dispatch($eventName, CollectionEvent $event) - { - $this->app['dispatcher']->dispatch($eventName, $event); - } - - public function enable(appbox $appbox) - { - $sql = 'UPDATE bas SET active = "1" WHERE base_id = :base_id'; - $stmt = $appbox->get_connection()->prepare($sql); - $stmt->execute([':base_id' => $this->get_base_id()]); - $stmt->closeCursor(); - - $this->reference->enable(); - - $this->delete_data_from_cache(); - $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); - $this->databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - - cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); - - return $this; - } - - public function get_ord() - { - return $this->reference->getDisplayIndex(); - } - - public function set_ord($ord) - { - $this->app->getApplicationBox()->set_collection_order($this, $ord); - $this->delete_data_from_cache(); - $this->app->getApplicationBox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); - - $this->reference->setDisplayIndex($ord); - - return $this; - } - - public function disable(appbox $appbox) - { - $sql = 'UPDATE bas SET active=0 WHERE base_id = :base_id'; - $stmt = $appbox->get_connection()->prepare($sql); - $stmt->execute([':base_id' => $this->get_base_id()]); - $stmt->closeCursor(); - - $this->reference->disable(); - - $this->delete_data_from_cache(); - $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); - $this->databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); - - return $this; - } - - public function empty_collection($pass_quantity = 100) - { - $pass_quantity = (int) $pass_quantity > 200 ? 200 : (int) $pass_quantity; - $pass_quantity = (int) $pass_quantity < 10 ? 10 : (int) $pass_quantity; - - $sql = "SELECT record_id FROM record WHERE coll_id = :coll_id - ORDER BY record_id DESC LIMIT 0, " . $pass_quantity; - - $stmt = $this->databox->get_connection()->prepare($sql); - $stmt->execute([':coll_id' => $this->get_coll_id()]); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - foreach ($rs as $row) { - $record = $this->databox->get_record($row['record_id']); - $record->delete(); - unset($record); - } - - return $this; - } - /** * @return bool */ @@ -459,6 +337,157 @@ EOT; return $this->databox->get_connection(); } + /** + * @param $publi + * @return $this + */ + public function set_public_presentation($publi) + { + $this->collectionVO->setPublicWatermark($publi); + $this->getCollectionRepository()->save($this->collectionVO); + + return $this; + } + + /** + * @param $name + * @return $this + * @throws Exception_InvalidArgument + */ + public function set_name($name) + { + try { + $this->collectionVO->setName($name); + } + catch (\InvalidArgumentException $e) { + throw new Exception_InvalidArgument(); + } + + $this->getCollectionRepository()->save($this->collectionVO); + $this->dispatch(CollectionEvents::NAME_CHANGED, new NameChangedEvent($this)); + + return $this; + } + + /** + * @param $code + * @param $label + * @return $this + */ + public function set_label($code, $label) + { + $this->collectionVO->setLabel($code, $label); + $this->getCollectionRepository()->save($this->collectionVO); + + return $this; + } + + /** + * @param $code + * @param bool $substitute + * @return string + */ + public function get_label($code, $substitute = true) + { + return $this->collectionVO->getLabel($code, $substitute); + } + + /** + * @return int + */ + public function get_ord() + { + return $this->reference->getDisplayIndex(); + } + + /** + * @param $ord + * @return $this + */ + public function set_ord($ord) + { + $this->reference->setDisplayIndex($ord); + $this->getReferenceRepository()->save($this->reference); + + return $this; + } + + /** + * @return int[]|null|string + */ + public function get_binary_minilogos() + { + return $this->collectionVO->getLogo(); + } + + /** + * @return int + */ + public function get_base_id() + { + return $this->reference->getBaseId(); + } + + /** + * @return int + */ + public function get_sbas_id() + { + return $this->reference->getDataboxId(); + } + + /** + * @return int + */ + public function get_coll_id() + { + return $this->reference->getCollectionId(); + } + + /** + * @return string + */ + public function get_prefs() + { + return $this->collectionVO->getPreferences(); + } + + /** + * @param DOMDocument $dom + * @return string + */ + public function set_prefs(DOMDocument $dom) + { + $this->collectionVO->setPreferences($dom->saveXML()); + $this->getCollectionRepository()->save($this->collectionVO); + + return $this->collectionVO->getPreferences(); + } + + /** + * @return string + */ + public function get_name() + { + return $this->collectionVO->getName(); + } + + /** + * @return string + */ + public function get_pub_wm() + { + return $this->collectionVO->getName(); + } + + /** + * @return bool + */ + public function is_available() + { + return true; + } + /** * @return int */ @@ -467,6 +496,44 @@ EOT; return $this->reference->getBaseId(); } + /** + * @return $this + */ + public function disable() + { + $this->reference->disable(); + $this->getReferenceRepository()->save($this->reference); + + cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); + + return $this; + } + + /** + * @return $this + */ + public function enable() + { + $this->reference->enable(); + $this->getReferenceRepository()->save($this->reference); + + cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); + + return $this; + } + + /** + * @param int $pass_quantity + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ + public function empty_collection($pass_quantity = 100) + { + $this->collectionService->emptyCollection($this->databox, $this->collectionVO, $pass_quantity); + + return $this; + } + /** * @param string $thumbnailType * @param File $file @@ -490,345 +557,133 @@ EOT; } } - public function set_public_presentation($publi) - { - if (in_array($publi, ['none', 'wm', 'stamp'])) { - $sql = 'UPDATE coll SET pub_wm = :pub_wm WHERE coll_id = :coll_id'; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':pub_wm' => $publi, ':coll_id' => $this->get_coll_id()]); - $stmt->closeCursor(); - - $this->pub_wm = $publi; - - $this->delete_data_from_cache(); - } - - return $this; - } - - public function set_name($name) - { - $name = trim(strip_tags($name)); - - if ($name === '') - throw new Exception_InvalidArgument (); - - $sql = "UPDATE coll SET asciiname = :asciiname - WHERE coll_id = :coll_id"; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':asciiname' => $name, ':coll_id' => $this->get_coll_id()]); - $stmt->closeCursor(); - - $this->name = $name; - - $this->delete_data_from_cache(); - - phrasea::reset_baseDatas($this->databox->get_appbox()); - - $this->dispatch(CollectionEvents::NAME_CHANGED, new NameChangedEvent($this)); - - return $this; - } - - public function set_label($code, $label) - { - if (!array_key_exists($code, $this->labels)) { - throw new InvalidArgumentException(sprintf('Code %s is not defined', $code)); - } - - $sql = "UPDATE coll SET label_$code = :label - WHERE coll_id = :coll_id"; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':label' => $label, ':coll_id' => $this->get_coll_id()]); - $stmt->closeCursor(); - - $this->labels[$code] = $label; - - $this->delete_data_from_cache(); - - phrasea::reset_baseDatas($this->databox->get_appbox()); - - return $this; - } - - public function get_label($code, $substitute = true) - { - if (!array_key_exists($code, $this->labels)) { - throw new InvalidArgumentException(sprintf('Code %s is not defined', $code)); - } - - if ($substitute) { - return isset($this->labels[$code]) ? $this->labels[$code] : $this->name; - } else { - return $this->labels[$code]; - } - } - + /** + * @return int|null + * @throws \Doctrine\DBAL\DBALException + */ public function get_record_amount() { - $sql = "SELECT COUNT(record_id) AS n FROM record WHERE coll_id = :coll_id"; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':coll_id' => $this->get_coll_id()]); - $rowbas = $stmt->fetch(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $amount = $rowbas ? (int) $rowbas["n"] : null; - - return $amount; + return $this->collectionService->getRecordCount($this->collectionVO); } + /** + * @return array + * @throws \Doctrine\DBAL\DBALException + */ public function get_record_details() { - $sql = "SELECT record.coll_id,name,COALESCE(asciiname, CONCAT('_',record.coll_id)) AS asciiname, - SUM(1) AS n, SUM(size) AS size - FROM record NATURAL JOIN subdef - INNER JOIN coll ON record.coll_id=coll.coll_id AND coll.coll_id = :coll_id - GROUP BY record.coll_id, subdef.name"; - - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':coll_id' => $this->get_coll_id()]); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $ret = []; - foreach ($rs as $row) { - $ret[] = [ - "coll_id" => (int) $row["coll_id"], - "name" => $row["name"], - "amount" => (int) $row["n"], - "size" => (int) $row["size"]]; - } - - return $ret; + return $this->collectionService->getRecordDetails($this->collectionVO); } + /** + * @param SplFileInfo $pathfile + * @return $this + */ public function update_logo(\SplFileInfo $pathfile = null) { - if (is_null($pathfile)) { - $this->binary_logo = null; - } else { - $this->binary_logo = file_get_contents($pathfile->getPathname()); + $fileContents = null; + + if (! is_null($pathfile)) { + $fileContents = file_get_contents($pathfile->getPathname()); } - $sql = "UPDATE coll SET logo = :logo, majLogo=NOW() WHERE coll_id = :coll_id"; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':logo' => $this->binary_logo, ':coll_id' => $this->get_coll_id()]); - $stmt->closeCursor(); + $this->collectionVO->setLogo($fileContents); + $this->getCollectionRepository()->save($this->collectionVO); return $this; } + /** + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ public function reset_watermark() { - $sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id) - WHERE r.coll_id = :coll_id AND r.type="image" AND s.name="preview"'; - - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':coll_id' => $this->get_coll_id()]); - - while ($row2 = $stmt->fetch(PDO::FETCH_ASSOC)) { - @unlink(p4string::addEndSlash($row2['path']) . 'watermark_' . $row2['file']); - } - $stmt->closeCursor(); + $this->collectionService->resetWatermark($this->collectionVO); return $this; } + /** + * @param null $record_id + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ public function reset_stamp($record_id = null) { - $sql = 'SELECT path, file FROM record r INNER JOIN subdef s USING(record_id) - WHERE r.coll_id = :coll_id - AND r.type="image" AND s.name IN ("preview", "document")'; - - $params = [':coll_id' => $this->get_coll_id()]; - - if ($record_id) { - $sql .= ' AND record_id = :record_id'; - $params[':record_id'] = $record_id; - } - - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute($params); - - while ($row2 = $stmt->fetch(PDO::FETCH_ASSOC)) { - @unlink(p4string::addEndSlash($row2['path']) . 'stamp_' . $row2['file']); - } - $stmt->closeCursor(); + $this->collectionService->resetStamp($this->collectionVO, $record_id); return $this; } + /** + * @throws \Doctrine\DBAL\DBALException + */ public function delete() { - while ($this->get_record_amount() > 0) { - $this->empty_collection(); - } - - $sql = "DELETE FROM coll WHERE coll_id = :coll_id"; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':coll_id' => $this->get_coll_id()]); - $stmt->closeCursor(); - - $appbox = $this->databox->get_appbox(); - - $sql = "DELETE FROM bas WHERE base_id = :base_id"; - $stmt = $appbox->get_connection()->prepare($sql); - $stmt->execute([':base_id' => $this->get_base_id()]); - $stmt->closeCursor(); - - $sql = "DELETE FROM basusr WHERE base_id = :base_id"; - $stmt = $appbox->get_connection()->prepare($sql); - $stmt->execute([':base_id' => $this->get_base_id()]); - $stmt->closeCursor(); - - $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); - - $this->get_databox()->delete_data_from_cache(databox::CACHE_COLLECTIONS); - $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); - phrasea::reset_baseDatas($appbox); - - return; - } - - public function get_binary_minilogos() - { - return $this->binary_logo; - } - - public function get_base_id() - { - return $this->reference->getBaseId(); - } - - public function get_sbas_id() - { - return $this->reference->getDataboxId(); - } - - public function get_coll_id() - { - return $this->reference->getCollectionId(); - } - - public function get_prefs() - { - return $this->preferences; - } - - public function set_prefs(DOMDocument $dom) - { - $this->preferences = $dom->saveXML(); - - $sql = "UPDATE coll SET prefs = :prefs WHERE coll_id = :coll_id"; - $stmt = $this->get_connection()->prepare($sql); - $stmt->execute([':prefs' => $this->preferences, ':coll_id' => $this->get_coll_id()]); - $stmt->closeCursor(); - - $this->delete_data_from_cache(); - - return $this->preferences; - } - - public function get_name() - { - return $this->name; - } - - public function get_pub_wm() - { - return $this->pub_wm; - } - - public function is_available() - { - return $this->available; + $this->collectionService->delete($this->databox, $this->collectionVO, $this->reference); } + /** + * @param Application $app + * @return $this + * @throws \Doctrine\DBAL\DBALException + */ public function unmount_collection(Application $app) { - $params = [':base_id' => $this->get_base_id()]; - - $query = $app['phraseanet.user-query']; - $total = $query->on_base_ids([$this->get_base_id()]) - ->include_phantoms(false) - ->include_special_users(true) - ->include_invite(true) - ->include_templates(true)->get_total(); - $n = 0; - while ($n < $total) { - $results = $query->limit($n, 50)->execute()->get_results(); - foreach ($results as $user) { - $app->getAclForUser($user)->delete_data_from_cache(ACL::CACHE_RIGHTS_SBAS); - $app->getAclForUser($user)->delete_data_from_cache(ACL::CACHE_RIGHTS_BAS); - } - $n+=50; - } - - $sql = "DELETE FROM basusr WHERE base_id = :base_id"; - $stmt = $app->getApplicationBox()->get_connection()->prepare($sql); - $stmt->execute($params); - $stmt->closeCursor(); - - $sql = "DELETE FROM bas WHERE base_id = :base_id"; - $stmt = $app->getApplicationBox()->get_connection()->prepare($sql); - $stmt->execute($params); - $stmt->closeCursor(); - - $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); - - phrasea::reset_baseDatas($app['phraseanet.appbox']); + $this->collectionService->unmountCollection($this->reference); return $this; } + /** + * @param $base_id + * @param User $user + * @return bool + */ public function set_admin($base_id, User $user) { - - $rights = [ - "canputinalbum" => "1", - "candwnldhd" => "1", - "nowatermark" => "1", - "candwnldpreview" => "1", - "cancmd" => "1", - "canadmin" => "1", - "actif" => "1", - "canreport" => "1", - "canpush" => "1", - "basusr_infousr" => "", - "canaddrecord" => "1", - "canmodifrecord" => "1", - "candeleterecord" => "1", - "chgstatus" => "1", - "imgtools" => "1", - "manage" => "1", - "modify_struct" => "1" - ]; - - $this->app->getAclForUser($user)->update_rights_to_base($base_id, $rights); + $this->collectionService->grantAdminRights($this->reference, $user); return true; } + /** + * @param null $option + * @return string + */ public function get_cache_key($option = null) { return 'collection_' . $this->get_coll_id() . ($option ? '_' . $option : ''); } + /** + * @param null $option + * @return string + */ public function get_data_from_cache($option = null) { return $this->databox->get_data_from_cache($this->get_cache_key($option)); } + /** + * @param $value + * @param null $option + * @param int $duration + * @return bool + */ public function set_data_to_cache($value, $option = null, $duration = 0) { return $this->databox->set_data_to_cache($value, $this->get_cache_key($option), $duration); } + /** + * @param null $option + */ public function delete_data_from_cache($option = null) { - self::getRepository($this->app, $this->reference->getDataboxId())->save($this); - - return $this->databox->delete_data_from_cache($this->get_cache_key($option)); + $this->getCollectionRepository()->save($this->collectionVO); + $this->databox->delete_data_from_cache($this->get_cache_key($option)); } /** @@ -849,7 +704,7 @@ EOT; } foreach ($element as $caninscript) { - if (false !== (Boolean) (string) $caninscript) { + if (false !== (bool) (string) $caninscript) { return true; } } @@ -860,14 +715,12 @@ EOT; /** * Gets terms of use. * - * @param \collection $collection - * * @return null|string */ public function getTermsOfUse() { if (false === $xml = simplexml_load_string($this->get_prefs())) { - return; + return null; } foreach ($xml->xpath('/baseprefs/cgu') as $sbpcgu) { From 569c2ff6d8b84fa0aadde24b14806805cd84923d Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 10 Jul 2015 17:32:09 +0200 Subject: [PATCH 13/17] Implement save collection VO --- .../Helper/ApplicationBoxAware.php | 10 ++ lib/Alchemy/Phrasea/Collection/Collection.php | 21 +++ .../Phrasea/Collection/CollectionFactory.php | 12 +- .../CollectionRepositoryRegistry.php | 5 + .../DbalCollectionReferenceRepository.php | 2 +- .../Repository/DbalCollectionRepository.php | 39 ++++- .../Controller/Admin/CollectionController.php | 4 +- lib/classes/appbox.php | 19 +++ lib/classes/collection.php | 137 +++++++----------- lib/classes/databox.php | 2 +- .../Controller/Admin/AdminCollectionTest.php | 6 +- .../Phrasea/Controller/Admin/DataboxTest.php | 4 +- 12 files changed, 165 insertions(+), 96 deletions(-) diff --git a/lib/Alchemy/Phrasea/Application/Helper/ApplicationBoxAware.php b/lib/Alchemy/Phrasea/Application/Helper/ApplicationBoxAware.php index 2f63347b8c..1bf48a4521 100644 --- a/lib/Alchemy/Phrasea/Application/Helper/ApplicationBoxAware.php +++ b/lib/Alchemy/Phrasea/Application/Helper/ApplicationBoxAware.php @@ -9,6 +9,8 @@ */ namespace Alchemy\Phrasea\Application\Helper; +use Alchemy\Phrasea\Collection\CollectionService; + trait ApplicationBoxAware { /** @var \appbox|callable */ @@ -61,6 +63,14 @@ trait ApplicationBoxAware return $this->applicationBox; } + /** + * @return CollectionService + */ + public function getCollectionService() + { + return $this['services.collection']; + } + /** * Find a registered Databoxes. * diff --git a/lib/Alchemy/Phrasea/Collection/Collection.php b/lib/Alchemy/Phrasea/Collection/Collection.php index b7e0d3f490..adce9e1705 100644 --- a/lib/Alchemy/Phrasea/Collection/Collection.php +++ b/lib/Alchemy/Phrasea/Collection/Collection.php @@ -3,6 +3,7 @@ namespace Alchemy\Phrasea\Collection; use Alchemy\Phrasea\Collection\Reference\CollectionReference; +use PHPExiftool\Exception\LogicException; class Collection { @@ -64,6 +65,14 @@ class Collection EOT; + $this->logo = ''; + $this->labels = array( + 'en' => '', + 'fr' => '', + 'de' => '', + 'nl' => '' + ); + $this->publicWatermark = ''; } /** @@ -82,6 +91,18 @@ EOT; return $this->collectionId; } + /** + * @param $collectionId + */ + public function setCollectionId($collectionId) + { + if ($this->collectionId > 0) { + throw new LogicException('Cannot change the ID of an existing collection.'); + } + + $this->collectionId = (int) $collectionId; + } + /** * @return string */ diff --git a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php index 482eb214ea..34c99c19b0 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionFactory.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionFactory.php @@ -33,7 +33,17 @@ class CollectionFactory throw new \InvalidArgumentException('Reference does not belong to given databoxId.'); } - return new \collection($this->app, $reference->getBaseId(), $reference, $row); + $collection = new Collection($databoxId, $row['coll_id'], $row['asciiname']); + + $collection->setLabel('en', $row['label_en']); + $collection->setLabel('fr', $row['label_fr']); + $collection->setLabel('de', $row['label_de']); + $collection->setLabel('nl', $row['label_nl']); + $collection->setLogo($row['logo']); + $collection->setPreferences($row['prefs']); + $collection->setPublicWatermark($row['pub_wm']); + + return new \collection($this->app, $collection, $reference, $row); } /** diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php b/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php index e64b25a5a4..8aea2df32a 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php @@ -67,6 +67,11 @@ class CollectionRepositoryRegistry throw new \OutOfBoundsException('No repository available for given base [baseId: ' . $baseId . ' ].'); } + public function purgeRegistry() + { + $this->baseIdMap = null; + } + private function loadBaseIdMap() { $references = $this->referenceRepository->findAll(); diff --git a/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php index 070186dc5c..63dd1eb06b 100644 --- a/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php @@ -25,7 +25,7 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository private static $insertQuery = 'INSERT INTO bas (sbas_id, server_coll_id, ord, active, aliases) VALUES (:databoxId, :collectionId, - (SELECT COALESCE(MAX(ord), 0) + 1 AS ord FROM bas WHERE sbas_id = :sbas_id), + (SELECT COALESCE(MAX(b.ord), 0) + 1 AS ord FROM bas b WHERE b.sbas_id = :databoxId), :isActive, :alias)'; private static $updateQuery = 'UPDATE bas SET ord = :displayIndex, active = :isActive, aliases = :alias diff --git a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php index b261f6f78e..0fe9827b06 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php @@ -11,9 +11,15 @@ use Doctrine\DBAL\Connection; class DbalCollectionRepository implements CollectionRepository { - private static $query = 'SELECT coll_id, asciiname, label_en, label_fr, label_de, label_nl, prefs, logo, majLogo, pub_wm + private static $selectQuery = 'SELECT coll_id, asciiname, label_en, label_fr, label_de, label_nl, prefs, logo, majLogo, pub_wm FROM coll'; + private static $insertQuery = 'INSERT INTO coll (asciiname, prefs, logo) VALUES (:name, :preferences, :logo)'; + + private static $updateQuery = 'UPDATE coll SET asciiname = :name, label_en = :labelEn, label_fr = :labelFr, + label_de = :labelDe, label_nl = :labelNl, prefs = :preferences, logo = :logo, + majLogo = :logoTimestamp, pub_wm = :publicWatermark WHERE coll_id = :collectionId'; + /** * @var int */ @@ -64,7 +70,7 @@ class DbalCollectionRepository implements CollectionRepository $params[':id_' . $reference->getCollectionId()] = $reference->getCollectionId(); } - $query = self::$query . sprintf(' WHERE coll_id IN (%s)', implode(', ', array_keys($params))); + $query = self::$selectQuery . sprintf(' WHERE coll_id IN (%s)', implode(', ', array_keys($params))); $rows = $this->connection->fetchAll($query, $params); return $this->collectionFactory->createMany($this->databoxId, $references, $rows); @@ -82,7 +88,7 @@ class DbalCollectionRepository implements CollectionRepository return null; } - $query = self::$query . ' WHERE coll_id = :collectionId'; + $query = self::$selectQuery . ' WHERE coll_id = :collectionId'; $row = $this->connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { @@ -105,7 +111,7 @@ class DbalCollectionRepository implements CollectionRepository return null; } - $query = self::$query . ' WHERE coll_id = :collectionId'; + $query = self::$selectQuery . ' WHERE coll_id = :collectionId'; $row = $this->connection->fetchAssoc($query, [ ':collectionId' => $reference->getCollectionId() ]); if ($row !== false) { @@ -117,6 +123,31 @@ class DbalCollectionRepository implements CollectionRepository public function save(Collection $collection) { + $isInsert = true; + $query = self::$insertQuery; + $parameters = array( + 'name' => $collection->getName(), + 'preferences' => $collection->getPreferences(), + 'logo' => $collection->getLogo() + ); + if ($collection->getCollectionId() > 0) { + $parameters['collectionId'] = $collection->getCollectionId(); + $parameters['labelEn'] = $collection->getLabel('en', false); + $parameters['labelFr'] = $collection->getLabel('fr', false); + $parameters['labelDe'] = $collection->getLabel('de', false); + $parameters['labelNl'] = $collection->getLabel('nl', false); + $parameters['logoTimestamp'] = $collection->getLogoUpdatedAt(); + $parameters['publicWatermark'] = $collection->getPublicWatermark(); + + $query = self::$updateQuery; + $isInsert = false; + } + + $this->connection->executeQuery($query, $parameters); + + if ($isInsert) { + $collection->setCollectionId($this->connection->lastInsertId()); + } } } diff --git a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php index b1c55ac100..8f98440394 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/CollectionController.php @@ -474,7 +474,7 @@ class CollectionController extends Controller if ($collection->get_record_amount() > 0) { $msg = $this->app->trans('Empty the collection before removing'); } else { - $collection->unmount_collection($this->app); + $collection->unmount(); $collection->delete(); $success = true; $msg = $this->app->trans('Successful removal'); @@ -525,7 +525,7 @@ class CollectionController extends Controller $collection = \collection::getByBaseId($this->app, $bas_id); try { - $collection->unmount_collection($this->app); + $collection->unmount(); $success = true; } catch (\Exception $e) { diff --git a/lib/classes/appbox.php b/lib/classes/appbox.php index 6df141463b..3c50f208bd 100644 --- a/lib/classes/appbox.php +++ b/lib/classes/appbox.php @@ -10,9 +10,11 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\CollectionService; use Alchemy\Phrasea\Core\Configuration\AccessRestriction; use Alchemy\Phrasea\Core\Connection\ConnectionSettings; use Alchemy\Phrasea\Core\Version\AppboxVersionRepository; +use Alchemy\Phrasea\Databox\DataboxConnectionProvider; use Alchemy\Phrasea\Databox\DataboxRepository; use Doctrine\ORM\Tools\SchemaTool; use MediaAlchemyst\Alchemyst; @@ -41,6 +43,10 @@ class appbox extends base * @var \databox[] */ protected $databoxes; + /** + * @var CollectionService + */ + protected $collectionService; public function __construct(Application $app) { @@ -289,6 +295,19 @@ class appbox extends base parent::delete_data_from_cache($option); } + public function getCollectionService() + { + if ($this->collectionService === null) { + $this->collectionService = new CollectionService( + $this->app, + $this->connection, + new DataboxConnectionProvider($this) + ); + } + + return $this->collectionService; + } + /** * @return AccessRestriction */ diff --git a/lib/classes/collection.php b/lib/classes/collection.php index b1e2c0ac28..9982b15bc0 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -25,7 +25,7 @@ use Alchemy\Phrasea\Core\Thumbnail\ThumbnailManager; use Alchemy\Phrasea\Model\Entities\User; use Symfony\Component\HttpFoundation\File\File; -class collection implements cache_cacheableInterface, ThumbnailedElement +class collection implements ThumbnailedElement { const PIC_LOGO = 'minilogos'; @@ -66,13 +66,12 @@ class collection implements cache_cacheableInterface, ThumbnailedElement $repository->save($collectionReference); - $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); + $app['repo.collections-registry']->purgeRegistry(); - phrasea::reset_baseDatas($appbox); + $collection = new self($app, $collection, $collectionReference); if (null !== $user) { - $collection->set_admin($collectionReference->getBaseId(), $user); + $collection->collectionService->grantAdminRights($collectionReference, $user); } $app['dispatcher']->dispatch(CollectionEvents::CREATED, new CreatedEvent($collection)); @@ -85,16 +84,10 @@ class collection implements cache_cacheableInterface, ThumbnailedElement $reference = new CollectionReference(0, $databox->get_sbas_id(), $coll_id, 0, true, ''); $app['repo.collection-references']->save($reference); + $app['repo.collections-registry']->purgeRegistry(); - $databox->get_appbox()->delete_data_from_cache(appbox::CACHE_LIST_BASES); - $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - - cache_databox::update($app, $databox->get_sbas_id(), 'structure'); - - phrasea::reset_baseDatas($databox->get_appbox()); - - $coll = self::getByBaseId($app, $reference->getBaseId()); - $coll->set_admin($reference->getBaseId(), $user); + $collection = self::getByBaseId($app, $reference->getBaseId()); + $collection->collectionService->grantAdminRights($collection->reference, $user); return $reference->getBaseId(); } @@ -103,7 +96,7 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $base_id_key = $base_id . '_' . ($printname ? '1' : '0'); - if ( ! isset(self::$_logos[$base_id_key])) { + if (!isset(self::$_logos[$base_id_key])) { if (is_file($app['root.path'] . '/config/minilogos/' . $base_id)) { $name = phrasea::bas_labels($base_id, $app); @@ -119,10 +112,11 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public static function getWatermark($base_id) { - if ( ! isset(self::$_watermarks['base_id'])) { + if (!isset(self::$_watermarks['base_id'])) { - if (is_file(__DIR__ . '/../../config/wm/' . $base_id)) + if (is_file(__DIR__ . '/../../config/wm/' . $base_id)) { self::$_watermarks['base_id'] = ''; + } } return isset(self::$_watermarks['base_id']) ? self::$_watermarks['base_id'] : ''; @@ -130,10 +124,11 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public static function getPresentation($base_id) { - if ( ! isset(self::$_presentations['base_id'])) { + if (!isset(self::$_presentations['base_id'])) { - if (is_file(__DIR__ . '/../../config/presentation/' . $base_id)) + if (is_file(__DIR__ . '/../../config/presentation/' . $base_id)) { self::$_presentations['base_id'] = ''; + } } return isset(self::$_presentations['base_id']) ? self::$_presentations['base_id'] : ''; @@ -141,10 +136,11 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public static function getStamp($base_id) { - if ( ! isset(self::$_stamps['base_id'])) { + if (!isset(self::$_stamps['base_id'])) { - if (is_file(__DIR__ . '/../../config/stamp/' . $base_id)) + if (is_file(__DIR__ . '/../../config/stamp/' . $base_id)) { self::$_stamps['base_id'] = ''; + } } return isset(self::$_stamps['base_id']) ? self::$_stamps['base_id'] : ''; @@ -157,7 +153,7 @@ class collection implements cache_cacheableInterface, ThumbnailedElement /** * @param Application $app - * @param int $base_id + * @param int $base_id * @return collection */ public static function getByBaseId(Application $app, $base_id) @@ -195,8 +191,8 @@ class collection implements cache_cacheableInterface, ThumbnailedElement /** * @param Application $app - * @param databox $databox - * @param int $coll_id + * @param databox $databox + * @param int $coll_id * @return collection */ public static function getByCollectionId(Application $app, databox $databox, $coll_id) @@ -260,8 +256,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $this->app = $app; $this->databox = $app->getApplicationBox()->get_databox($reference->getDataboxId()); + $this->collectionService = $app->getApplicationBox()->getCollectionService(); - $this->collection = $collection; + $this->collectionVO = $collection; $this->reference = $reference; } @@ -294,12 +291,13 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $this->app = $app; $this->databox = $app->getApplicationBox()->get_databox($this->reference->getDataboxId()); + $this->collectionService = $app->getApplicationBox()->getCollectionService(); } public function __sleep() { return array( - 'collection', + 'collectionVO', 'reference' ); } @@ -345,6 +343,7 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $this->collectionVO->setPublicWatermark($publi); $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); return $this; } @@ -358,12 +357,13 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { try { $this->collectionVO->setName($name); - } - catch (\InvalidArgumentException $e) { + } catch (\InvalidArgumentException $e) { throw new Exception_InvalidArgument(); } $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); + $this->dispatch(CollectionEvents::NAME_CHANGED, new NameChangedEvent($this)); return $this; @@ -377,7 +377,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function set_label($code, $label) { $this->collectionVO->setLabel($code, $label); + $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); return $this; } @@ -407,7 +409,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function set_ord($ord) { $this->reference->setDisplayIndex($ord); + $this->getReferenceRepository()->save($this->reference); + $this->app['repo.collections-registry']->purgeRegistry(); return $this; } @@ -459,7 +463,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function set_prefs(DOMDocument $dom) { $this->collectionVO->setPreferences($dom->saveXML()); + $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); return $this->collectionVO->getPreferences(); } @@ -502,7 +508,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function disable() { $this->reference->disable(); + $this->getReferenceRepository()->save($this->reference); + $this->app['repo.collections-registry']->purgeRegistry(); cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); @@ -515,7 +523,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function enable() { $this->reference->enable(); + $this->getReferenceRepository()->save($this->reference); + $this->app['repo.collections-registry']->purgeRegistry(); cache_databox::update($this->app, $this->databox->get_sbas_id(), 'structure'); @@ -583,12 +593,14 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $fileContents = null; - if (! is_null($pathfile)) { + if (!is_null($pathfile)) { $fileContents = file_get_contents($pathfile->getPathname()); } $this->collectionVO->setLogo($fileContents); + $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); return $this; } @@ -601,6 +613,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $this->collectionService->resetWatermark($this->collectionVO); + $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); + return $this; } @@ -613,6 +628,9 @@ class collection implements cache_cacheableInterface, ThumbnailedElement { $this->collectionService->resetStamp($this->collectionVO, $record_id); + $this->getCollectionRepository()->save($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); + return $this; } @@ -622,70 +640,25 @@ class collection implements cache_cacheableInterface, ThumbnailedElement public function delete() { $this->collectionService->delete($this->databox, $this->collectionVO, $this->reference); + + $this->getCollectionRepository()->delete($this->collectionVO); + $this->app['repo.collections-registry']->purgeRegistry(); } /** - * @param Application $app * @return $this * @throws \Doctrine\DBAL\DBALException */ - public function unmount_collection(Application $app) + public function unmount() { $this->collectionService->unmountCollection($this->reference); + $this->getReferenceRepository()->delete($this->reference); + $this->app['repo.collections-registry']->purgeRegistry(); + return $this; } - /** - * @param $base_id - * @param User $user - * @return bool - */ - public function set_admin($base_id, User $user) - { - $this->collectionService->grantAdminRights($this->reference, $user); - - return true; - } - - /** - * @param null $option - * @return string - */ - public function get_cache_key($option = null) - { - return 'collection_' . $this->get_coll_id() . ($option ? '_' . $option : ''); - } - - /** - * @param null $option - * @return string - */ - public function get_data_from_cache($option = null) - { - return $this->databox->get_data_from_cache($this->get_cache_key($option)); - } - - /** - * @param $value - * @param null $option - * @param int $duration - * @return bool - */ - public function set_data_to_cache($value, $option = null, $duration = 0) - { - return $this->databox->set_data_to_cache($value, $this->get_cache_key($option), $duration); - } - - /** - * @param null $option - */ - public function delete_data_from_cache($option = null) - { - $this->getCollectionRepository()->save($this->collectionVO); - $this->databox->delete_data_from_cache($this->get_cache_key($option)); - } - /** * Tells whether registration is activated for provided collection or not. * @@ -704,7 +677,7 @@ class collection implements cache_cacheableInterface, ThumbnailedElement } foreach ($element as $caninscript) { - if (false !== (bool) (string) $caninscript) { + if (false !== (bool)(string)$caninscript) { return true; } } diff --git a/lib/classes/databox.php b/lib/classes/databox.php index 784c536a08..deb0e215c1 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -380,7 +380,7 @@ class databox extends base implements \Alchemy\Phrasea\Core\Thumbnail\Thumbnaile public function unmount_databox() { foreach ($this->get_collections() as $collection) { - $collection->unmount_collection($this->app); + $collection->unmount(); } $query = $this->app['phraseanet.user-query']; diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php index 5ad9553753..825e618b88 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php @@ -30,7 +30,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase self::$DI['app']['acl'] = new ACLProvider(self::$DI['app']); foreach (self::$createdCollections as $collection) { try { - $collection->unmount_collection(self::$DI['app']); + $collection->unmount(); } catch (\Exception $e) { } @@ -440,7 +440,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $json = $this->getJson(self::$DI['client']->getResponse()); $this->assertTrue($json->success); $this->assertEquals($collection->get_name(), 'test_rename_coll'); - $collection->unmount_collection(self::$DI['app']); + $collection->unmount(); $collection->delete(); } @@ -469,7 +469,7 @@ class AdminCollectionTest extends \PhraseanetAuthenticatedWebTestCase $this->assertEquals($collection->get_label('nl'), 'netherlands label'); $this->assertEquals($collection->get_label('fr'), 'label français'); $this->assertEquals($collection->get_label('en'), 'label à l\'anglaise'); - $collection->unmount_collection(self::$DI['app']); + $collection->unmount(); $collection->delete(); } diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php index a074ec40b9..889d677c55 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php @@ -34,7 +34,7 @@ class DataboxTest extends \PhraseanetAuthenticatedWebTestCase foreach (self::$createdCollections as $collection) { try { - $collection->unmount_collection(self::$DI['app']); + $collection->unmount(); } catch (\Exception $e) { } @@ -515,7 +515,7 @@ class DataboxTest extends \PhraseanetAuthenticatedWebTestCase $this->setAdmin(true); $collection = $this->createOneCollection(); - $collection->unmount_collection(self::$DI['app']); + $collection->unmount(); self::$DI['client']->request('POST', '/admin/databox/' . $collection->get_sbas_id() . '/collection/' . $collection->get_coll_id() . '/mount/', [ 'othcollsel' => self::$DI['collection']->get_base_id() From fcb369486ab9ba869e0e2e9d43d589f22fd793bb Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 10 Jul 2015 17:45:54 +0200 Subject: [PATCH 14/17] Fix undefined method call --- .../Collection/Repository/ArrayCacheCollectionRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php index 2902841f6b..45df2e1f6f 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php @@ -54,7 +54,7 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->collectionRepository->save($collection); if ($this->collectionCache !== null) { - $this->collectionCache[$collection->get_coll_id()] = $collection; + $this->collectionCache = null; } } } From d8f498aa26e848d7a789008d7e61ecb9c8ce0b7a Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 10 Jul 2015 18:39:36 +0200 Subject: [PATCH 15/17] Improve collection reference caching and remove legacy maps --- .../Collection/CollectionRepository.php | 8 +- .../CollectionRepositoryRegistry.php | 14 +++ .../Phrasea/Collection/CollectionService.php | 2 - ...rrayCacheCollectionReferenceRepository.php | 110 ++++++++++++++++++ .../CollectionReferenceRepository.php | 6 + .../DbalCollectionReferenceRepository.php | 15 +++ .../ArrayCacheCollectionRepository.php | 11 +- .../Repository/CachedCollectionRepository.php | 9 ++ .../Repository/DbalCollectionRepository.php | 11 ++ .../Provider/RepositoriesServiceProvider.php | 7 +- lib/classes/collection.php | 12 ++ lib/classes/phrasea.php | 101 +++++++--------- 12 files changed, 238 insertions(+), 68 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Collection/Reference/ArrayCacheCollectionReferenceRepository.php diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php index aadf24148c..865ece521d 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepository.php @@ -2,7 +2,7 @@ namespace Alchemy\Phrasea\Collection; -interface CollectionRepository +interface CollectionRepository { /** @@ -21,4 +21,10 @@ interface CollectionRepository * @return void */ public function save(Collection $collection); + + /** + * @param Collection $collection + * @return void + */ + public function delete(Collection $collection); } diff --git a/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php b/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php index 8aea2df32a..6acc5f0ee2 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionRepositoryRegistry.php @@ -2,6 +2,7 @@ namespace Alchemy\Phrasea\Collection; +use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository; class CollectionRepositoryRegistry @@ -9,6 +10,11 @@ class CollectionRepositoryRegistry private $baseIdMap = null; + /** + * @var Application + */ + private $application; + /** * @var CollectionRepository[] */ @@ -25,13 +31,16 @@ class CollectionRepositoryRegistry private $repositoryFactory; /** + * @param Application $app * @param CollectionRepositoryFactory $collectionRepositoryFactory * @param CollectionReferenceRepository $referenceRepository */ public function __construct( + Application $app, CollectionRepositoryFactory $collectionRepositoryFactory, CollectionReferenceRepository $referenceRepository ) { + $this->application = $app; $this->repositoryFactory = $collectionRepositoryFactory; $this->referenceRepository = $referenceRepository; } @@ -70,6 +79,11 @@ class CollectionRepositoryRegistry public function purgeRegistry() { $this->baseIdMap = null; + + $appBox = $this->application->getApplicationBox(); + + \phrasea::reset_baseDatas($appBox); + \phrasea::reset_sbasDatas($appBox); } private function loadBaseIdMap() diff --git a/lib/Alchemy/Phrasea/Collection/CollectionService.php b/lib/Alchemy/Phrasea/Collection/CollectionService.php index 3707aa0157..6e75c87780 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionService.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionService.php @@ -162,8 +162,6 @@ class CollectionService $stmt->execute([':base_id' => $reference->getBaseId()]); $stmt->closeCursor(); - $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); - return; } diff --git a/lib/Alchemy/Phrasea/Collection/Reference/ArrayCacheCollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/Reference/ArrayCacheCollectionReferenceRepository.php new file mode 100644 index 0000000000..373eeab202 --- /dev/null +++ b/lib/Alchemy/Phrasea/Collection/Reference/ArrayCacheCollectionReferenceRepository.php @@ -0,0 +1,110 @@ +repository = $referenceRepository; + } + + /** + * @return CollectionReference[] + */ + public function findAll() + { + if ($this->referenceCache === null) { + $this->referenceCache = $this->repository->findAll(); + } + + return $this->referenceCache; + } + + /** + * @param int $databoxId + * @return CollectionReference[] + */ + public function findAllByDatabox($databoxId) + { + $references = $this->findAll(); + $found = array(); + + foreach ($references as $reference) { + if ($reference->getDataboxId() == $databoxId) { + $found[$reference->getBaseId()] = $reference; + } + } + + return $found; + } + + /** + * @param int $baseId + * @return CollectionReference|null + */ + public function find($baseId) + { + $references = $this->findAll(); + + if (isset($references[$baseId])) { + return $references[$baseId]; + } + + return null; + } + + /** + * @param int $databoxId + * @param int $collectionId + * @return CollectionReference|null + */ + public function findByCollectionId($databoxId, $collectionId) + { + $references = $this->findAll(); + + foreach ($references as $reference) { + if ($reference->getCollectionId() == $collectionId) { + return $reference; + } + } + + return null; + } + + /** + * @param CollectionReference $reference + * @return void + */ + public function save(CollectionReference $reference) + { + $this->repository->save($reference); + + if ($this->referenceCache !== null) { + $this->referenceCache[$reference->getBaseId()] = $reference; + } + } + + /** + * @param CollectionReference $reference + * @return void + */ + public function delete(CollectionReference $reference) + { + $this->repository->delete($reference); + + if ($this->referenceCache !== null) { + unset($this->referenceCache[$reference->getBaseId()]); + } + } +} diff --git a/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php index b90b02e1de..48dbfc94f5 100644 --- a/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/CollectionReferenceRepository.php @@ -33,4 +33,10 @@ interface CollectionReferenceRepository * @return void */ public function save(CollectionReference $reference); + + /** + * @param CollectionReference $reference + * @return void + */ + public function delete(CollectionReference $reference); } diff --git a/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php b/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php index 63dd1eb06b..22ff361ed7 100644 --- a/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Reference/DbalCollectionReferenceRepository.php @@ -31,6 +31,8 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository private static $updateQuery = 'UPDATE bas SET ord = :displayIndex, active = :isActive, aliases = :alias WHERE base_id = :baseId'; + private static $deleteQuery = 'DELETE FROM bas WHERE base_id = :baseId'; + /** * @var Connection */ @@ -126,6 +128,19 @@ class DbalCollectionReferenceRepository implements CollectionReferenceRepository } } + /** + * @param CollectionReference $collectionReference + * @throws \Doctrine\DBAL\DBALException + */ + public function delete(CollectionReference $collectionReference) + { + $parameters = [ + 'baseId' => $collectionReference->getBaseId() + ]; + + $this->connection->executeQuery(self::$deleteQuery, $parameters); + } + /** * @param array $row * @return CollectionReference diff --git a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php index 45df2e1f6f..0373e02bf3 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php @@ -54,7 +54,16 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->collectionRepository->save($collection); if ($this->collectionCache !== null) { - $this->collectionCache = null; + $this->collectionCache[$collection->getCollectionId()] = $collection; + } + } + + public function delete(Collection $collection) + { + $this->collectionRepository->delete($collection); + + if (isset($this->collectionCache[$collection->getCollectionId()])) { + unset($this->collectionCache[$collection->getCollectionId()]); } } } diff --git a/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php index 5dd84f7c53..a7a414aee4 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/CachedCollectionRepository.php @@ -96,6 +96,15 @@ final class CachedCollectionRepository implements CollectionRepository $this->cache->delete($cacheKey); } + public function delete(Collection $collection) + { + $this->repository->delete($collection); + + $cacheKey = hash('sha256', $this->cacheKey); + + $this->cache->delete($cacheKey); + } + private function putInCache($key, $value) { $this->cache->save($key, $value); diff --git a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php index 0fe9827b06..860dcd1e5c 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/DbalCollectionRepository.php @@ -20,6 +20,8 @@ class DbalCollectionRepository implements CollectionRepository label_de = :labelDe, label_nl = :labelNl, prefs = :preferences, logo = :logo, majLogo = :logoTimestamp, pub_wm = :publicWatermark WHERE coll_id = :collectionId'; + private static $deleteQuery = 'DELETE FROM coll WHERE coll_id = :collectionId'; + /** * @var int */ @@ -150,4 +152,13 @@ class DbalCollectionRepository implements CollectionRepository $collection->setCollectionId($this->connection->lastInsertId()); } } + + public function delete(Collection $collection) + { + $parameters = [ + 'collectionId' => $collection->getCollectionId() + ]; + + $this->connection->executeQuery(self::$deleteQuery, $parameters); + } } diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index 58bc0839a1..b8e3cffbd0 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -17,6 +17,7 @@ use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; use Alchemy\Phrasea\Collection\Factory\ArrayCachedCollectionRepositoryFactory; use Alchemy\Phrasea\Collection\Factory\CachedCollectionRepositoryFactory; use Alchemy\Phrasea\Collection\Factory\DbalCollectionRepositoryFactory; +use Alchemy\Phrasea\Collection\Reference\ArrayCacheCollectionReferenceRepository; use Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository; use Alchemy\Phrasea\Collection\Repository\ArrayCacheCollectionRepository; use Alchemy\Phrasea\Collection\Repository\CachedCollectionRepository; @@ -150,7 +151,9 @@ class RepositoriesServiceProvider implements ServiceProviderInterface }); $app['repo.collection-references'] = $app->share(function (PhraseaApplication $app) { - return new DbalCollectionReferenceRepository($app->getApplicationBox()->get_connection()); + $repository = new DbalCollectionReferenceRepository($app->getApplicationBox()->get_connection()); + + return new ArrayCacheCollectionReferenceRepository($repository); }); $app['repo.collections-registry'] = $app->share(function (PhraseaApplication $app) { @@ -172,7 +175,7 @@ class RepositoriesServiceProvider implements ServiceProviderInterface $repositoryFactory = new ArrayCachedCollectionRepositoryFactory($repositoryFactory); - return new CollectionRepositoryRegistry($repositoryFactory, $app['repo.collection-references']); + return new CollectionRepositoryRegistry($app, $repositoryFactory, $app['repo.collection-references']); }); } diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 9982b15bc0..269f8e79d1 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -302,6 +302,14 @@ class collection implements ThumbnailedElement ); } + /** + * @return CollectionVO + */ + public function getCollection() + { + return $this->collectionVO; + } + /** * @return CollectionReference */ @@ -642,6 +650,8 @@ class collection implements ThumbnailedElement $this->collectionService->delete($this->databox, $this->collectionVO, $this->reference); $this->getCollectionRepository()->delete($this->collectionVO); + + $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); $this->app['repo.collections-registry']->purgeRegistry(); } @@ -654,6 +664,8 @@ class collection implements ThumbnailedElement $this->collectionService->unmountCollection($this->reference); $this->getReferenceRepository()->delete($this->reference); + + $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); $this->app['repo.collections-registry']->purgeRegistry(); return $this; diff --git a/lib/classes/phrasea.php b/lib/classes/phrasea.php index 1b1f6faa83..c907c13ba6 100644 --- a/lib/classes/phrasea.php +++ b/lib/classes/phrasea.php @@ -10,6 +10,8 @@ */ use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Collection\CollectionRepositoryRegistry; +use Alchemy\Phrasea\Collection\Reference\CollectionReferenceRepository; use Symfony\Component\Translation\TranslatorInterface; class phrasea @@ -98,49 +100,28 @@ class phrasea public static function sbasFromBas(Application $app, $base_id) { - if (!self::$_bas2sbas) { - try { - $data = $app->getApplicationBox()->get_data_from_cache(self::CACHE_SBAS_FROM_BAS); - if (!$data) { - throw new \Exception('Could not get sbas from cache'); - } - self::$_bas2sbas = $data; - } catch (\Exception $e) { - $sql = 'SELECT base_id, sbas_id FROM bas'; - $stmt = $app->getApplicationBox()->get_connection()->prepare($sql); - $stmt->execute(); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); + /** @var CollectionReferenceRepository $repository */ + $repository = $app['repo.collection-references']; + $reference = $repository->find($base_id); - foreach ($rs as $row) { - self::$_bas2sbas[$row['base_id']] = (int) $row['sbas_id']; - } - - $app->getApplicationBox()->set_data_to_cache(self::$_bas2sbas, self::CACHE_SBAS_FROM_BAS); - } + if ($reference) { + return $reference->getDataboxId(); } - return isset(self::$_bas2sbas[$base_id]) ? self::$_bas2sbas[$base_id] : false; + return false; } public static function baseFromColl($sbas_id, $coll_id, Application $app) { - if (!self::$_coll2bas) { - $conn = $app->getApplicationBox()->get_connection(); - $sql = 'SELECT base_id, server_coll_id, sbas_id FROM bas'; - $stmt = $conn->prepare($sql); - $stmt->execute(); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); + /** @var CollectionReferenceRepository $repository */ + $repository = $app['repo.collection-references']; + $reference = $repository->findByCollectionId($sbas_id, $coll_id); - foreach ($rs as $row) { - if (!isset(self::$_coll2bas[$row['sbas_id']])) - self::$_coll2bas[$row['sbas_id']] = []; - self::$_coll2bas[$row['sbas_id']][$row['server_coll_id']] = (int) $row['base_id']; - } + if ($reference) { + return $reference->getBaseId(); } - return isset(self::$_coll2bas[$sbas_id][$coll_id]) ? self::$_coll2bas[$sbas_id][$coll_id] : false; + return false; } public static function reset_baseDatas(appbox $appbox) @@ -175,20 +156,15 @@ class phrasea public static function collFromBas(Application $app, $base_id) { - if (!self::$_bas2coll) { - $conn = $app->getApplicationBox()->get_connection(); - $sql = 'SELECT base_id, server_coll_id FROM bas'; - $stmt = $conn->prepare($sql); - $stmt->execute(); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); + /** @var CollectionReferenceRepository $repository */ + $repository = $app['repo.collection-references']; + $reference = $repository->find($base_id); - foreach ($rs as $row) { - self::$_bas2coll[$row['base_id']] = (int) $row['server_coll_id']; - } + if ($reference) { + return $reference->getCollectionId(); } - return isset(self::$_bas2coll[$base_id]) ? self::$_bas2coll[$base_id] : false; + return false; } public static function sbas_names($sbas_id, Application $app) @@ -234,27 +210,28 @@ class phrasea public static function bas_labels($base_id, Application $app) { - if (!self::$_bas_labels) { - try { - self::$_bas_labels = $app->getApplicationBox()->get_data_from_cache(self::CACHE_BAS_LABELS); - } catch (\Exception $e) { - foreach ($app->getDataboxes() as $databox) { - foreach ($databox->get_collections() as $collection) { - self::$_bas_labels[$collection->get_base_id()] = [ - 'fr' => $collection->get_label('fr'), - 'en' => $collection->get_label('en'), - 'de' => $collection->get_label('de'), - 'nl' => $collection->get_label('nl'), - ]; - } - } + /** @var CollectionReferenceRepository $repository */ + $referenceRepository = $app['repo.collection-references']; + $reference = $referenceRepository->find($base_id); - $app->getApplicationBox()->set_data_to_cache(self::$_bas_labels, self::CACHE_BAS_LABELS); - } + if (! $reference) { + return 'Unknown collection'; } - if (isset(self::$_bas_labels[$base_id]) && isset(self::$_bas_labels[$base_id][$app['locale']])) { - return self::$_bas_labels[$base_id][$app['locale']]; + /** @var CollectionRepositoryRegistry $collectionRepositoryRegistry */ + $collectionRepositoryRegistry = $app['repo.collections-registry']; + $collectionRepository = $collectionRepositoryRegistry->getRepositoryByDatabox($reference->getDataboxId()); + + $collection = $collectionRepository->find($reference->getCollectionId()); + + if (! $collection) { + throw new \RuntimeException('Missing collection ' . $base_id . '.'); + } + + $labels = $collection->getCollection()->getLabels(); + + if (isset($labels[$app['locale']])) { + return $labels[$app['locale']]; } return 'Unknown collection'; From e5e96eafeb14adf06fdd1513f509c2afcd0f3608 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 10 Jul 2015 18:45:21 +0200 Subject: [PATCH 16/17] Fix cache invalidation on save --- .../Collection/Repository/ArrayCacheCollectionRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php index 0373e02bf3..3a5bc69951 100644 --- a/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php +++ b/lib/Alchemy/Phrasea/Collection/Repository/ArrayCacheCollectionRepository.php @@ -54,7 +54,7 @@ class ArrayCacheCollectionRepository implements CollectionRepository $this->collectionRepository->save($collection); if ($this->collectionCache !== null) { - $this->collectionCache[$collection->getCollectionId()] = $collection; + $this->collectionCache = null; } } From 232b72269a19554b354445e0e3b24ce727709533 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 10 Jul 2015 19:04:54 +0200 Subject: [PATCH 17/17] Fix call on non object --- .../Phrasea/Collection/CollectionService.php | 2 -- .../Controller/Prod/PropertyController.php | 2 +- lib/classes/collection.php | 22 ++++++++++++++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/Alchemy/Phrasea/Collection/CollectionService.php b/lib/Alchemy/Phrasea/Collection/CollectionService.php index 6e75c87780..0cb33fc4fe 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionService.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionService.php @@ -233,8 +233,6 @@ class CollectionService $stmt = $this->connection->prepare($sql); $stmt->execute($params); $stmt->closeCursor(); - - $this->app['manipulator.registration']->deleteRegistrationsOnCollection($this); } /** diff --git a/lib/Alchemy/Phrasea/Controller/Prod/PropertyController.php b/lib/Alchemy/Phrasea/Controller/Prod/PropertyController.php index a6bdf3c5dd..18c89aaa55 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/PropertyController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/PropertyController.php @@ -36,7 +36,7 @@ class PropertyController extends Controller ])); } - $databox = current($records->databoxes()); + $databox = reset($records->databoxes()); $statusStructure = $databox->getStatusStructure(); $recordsStatuses = []; diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 269f8e79d1..070c566f6e 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -25,7 +25,7 @@ use Alchemy\Phrasea\Core\Thumbnail\ThumbnailManager; use Alchemy\Phrasea\Model\Entities\User; use Symfony\Component\HttpFoundation\File\File; -class collection implements ThumbnailedElement +class collection implements ThumbnailedElement, cache_cacheableInterface { const PIC_LOGO = 'minilogos'; @@ -712,4 +712,24 @@ class collection implements ThumbnailedElement return $sbpcgu->saveXML(); } } + + public function get_cache_key($option = null) + { + return 'collection_' . $this->collectionVO->getCollectionId() . ($option ? '_' . $option : ''); + } + + public function get_data_from_cache($option = null) + { + return $this->databox->get_data_from_cache($this->get_cache_key($option)); + } + + public function set_data_to_cache($value, $option = null, $duration = 0) + { + return $this->databox->set_data_to_cache($value, $this->get_cache_key($option), $duration); + } + + public function delete_data_from_cache($option = null) + { + $this->databox->delete_data_from_cache($this->get_cache_key($option)); + } }