From 8e693964dfb21ff3b7892a01d405dcef71bcf064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Wed, 11 May 2016 15:05:39 +0200 Subject: [PATCH] Refactor getChildren() and get_grouping_parents() --- .../Provider/RepositoriesServiceProvider.php | 2 +- .../Databox/Record/LegacyRecordRepository.php | 176 +++++++++++++++--- .../Databox/Record/RecordRepository.php | 21 +++ lib/classes/record/adapter.php | 78 +------- 4 files changed, 180 insertions(+), 97 deletions(-) diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index be6bae51d3..80f9d2286c 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -168,7 +168,7 @@ class RepositoriesServiceProvider implements ServiceProviderInterface }); $app['repo.records.factory'] = $app->protect(function (\databox $databox) use ($app) { - return new LegacyRecordRepository($app, $databox); + return new LegacyRecordRepository($app, $databox, $app['conf']->get(['main', 'key'])); }); $app['repo.collection-references'] = $app->share(function (PhraseaApplication $app) { diff --git a/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php b/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php index 53d68bfc0c..f511d8181a 100644 --- a/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php +++ b/lib/Alchemy/Phrasea/Databox/Record/LegacyRecordRepository.php @@ -11,19 +11,32 @@ namespace Alchemy\Phrasea\Databox\Record; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Cache\Exception; +use Alchemy\Phrasea\Model\Entities\User; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Query\QueryBuilder; class LegacyRecordRepository implements RecordRepository { - /** @var Application */ + /** + * @var Application + */ private $app; - /** @var \databox */ + + /** + * @var \databox + */ private $databox; - public function __construct(Application $app, \databox $databox) + /** + * @var string + */ + private $site; + + public function __construct(Application $app, \databox $databox, $site) { $this->app = $app; $this->databox = $databox; + $this->site = $site; } public function find($record_id, $number = null) @@ -107,30 +120,124 @@ class LegacyRecordRepository implements RecordRepository return $this->mapRecordsFromResultSet($result); } + public function findChildren(array $storyIds, $user = null) + { + if (!$storyIds) { + return []; + } + + $connection = $this->databox->get_connection(); + + $selects = $this->getRecordSelects(); + array_unshift($selects, 's.rid_parent as story_id'); + + $builder = $connection->createQueryBuilder(); + $builder + ->select($selects) + ->from('regroup', 's') + ->innerJoin('s', 'record', 'r', 'r.record_id = s.rid_child') + ->where( + 's.rid_parent IN (:storyIds)', + 'r.parent_record_id = 0' + ) + ->setParameter('storyIds', $storyIds, Connection::PARAM_INT_ARRAY) + ; + + if (null !== $user) { + $this->addUserFilter($builder, $user); + } + + $data = $connection->fetchAll($builder->getSQL(), $builder->getParameters(), $builder->getParameterTypes()); + $records = $this->mapRecordsFromResultSet($data); + + $selections = array_map(function () { + return new \set_selection($this->app); + }, $storyIds); + + + foreach ($records as $index => $child) { + /** @var \set_selection $selection */ + $selection = $selections[$data[$index]['story_id']]; + + $child->setNumber($selection->get_count() + 1); + + $selection->add_element($child); + } + + return $selections; + } + + public function findParents(array $recordIds, $user = null) + { + if (!$recordIds) { + return []; + } + + $connection = $this->databox->get_connection(); + + $builder = $connection->createQueryBuilder(); + $builder + ->select($this->getRecordSelects()) + ->from('regroup', 's') + ->innerJoin('s', 'record', 'r', 'r.record_id = s.rid_parent') + ->where( + 's.rid_child IN (:recordIds)', + 'r.parent_record_id = 1' + ) + ->setParameter('recordIds', $recordIds, Connection::PARAM_INT_ARRAY) + ; + + if (null !== $user) { + $this->addUserFilter($builder, $user); + } + + $data = $connection->fetchAll($builder->getSQL(), $builder->getParameters(), $builder->getParameterTypes()); + $stories = $this->mapRecordsFromResultSet($data); + + $selections = array_map(function () { + return new \set_selection($this->app); + }, $recordIds); + + + foreach ($stories as $index => $child) { + /** @var \set_selection $selection */ + $selection = $selections[$data[$index]['record_id']]; + + $child->setNumber($selection->get_count() + 1); + + $selection->add_element($child); + } + + return $selections; + } + /** - * @return \Doctrine\DBAL\Query\QueryBuilder + * @return QueryBuilder */ private function createSelectBuilder() { - $connection = $this->databox->get_connection(); - - return $connection->createQueryBuilder() - ->select( - 'coll_id AS collection_id', - 'record_id', - 'credate AS created', - 'uuid', - 'moddate AS updated', - 'parent_record_id AS isStory', - $connection->quoteIdentifier('type'), - 'originalname AS originalName', - 'sha256', - 'mime', - 'LPAD(BIN(status), 32, \'0\') as status' - ) + return $this->databox->get_connection()->createQueryBuilder() + ->select($this->getRecordSelects()) ->from('record', 'r'); } + private function getRecordSelects() + { + return [ + 'r.coll_id AS collection_id', + 'r.record_id', + 'r.credate AS created', + 'r.uuid', + 'r.moddate AS updated', + 'r.parent_record_id AS isStory', + 'r.type', + 'r.originalname AS originalName', + 'r.sha256', + 'r.mime', + 'LPAD(BIN(r.status), 32, \'0\') as status', + ]; + } + /** * @param array $result * @return \record_adapter[] @@ -139,8 +246,8 @@ class LegacyRecordRepository implements RecordRepository { $records = []; - foreach ($result as $row) { - $records[] = $this->mapRecordFromResultRow($row); + foreach ($result as $index => $row) { + $records[$index] = $this->mapRecordFromResultRow($row); } return $records; @@ -162,4 +269,29 @@ class LegacyRecordRepository implements RecordRepository return $record; } + + /** + * @param QueryBuilder $builder + * @param int|User $user + * @return void + */ + private function addUserFilter(QueryBuilder $builder, $user) + { + $subBuilder = $builder->getConnection()->createQueryBuilder(); + + $subBuilder + ->select('1') + ->from('collusr', 'c') + ->where( + 'c.usr_id = :userId', + 'c.site = :site', + '((r.status ^ c.mask_xor) & c.mask_and) = 0', + 'c.coll_id = r.coll_id' + ); + + $builder + ->andWhere(sprintf('EXISTS(%s)', $subBuilder->getSQL())) + ->setParameter('userId', $user instanceof User ? $user->getId() : (int)$user) + ->setParameter('site', $this->site); + } } diff --git a/lib/Alchemy/Phrasea/Databox/Record/RecordRepository.php b/lib/Alchemy/Phrasea/Databox/Record/RecordRepository.php index 6cdc72412c..0da49bb00f 100644 --- a/lib/Alchemy/Phrasea/Databox/Record/RecordRepository.php +++ b/lib/Alchemy/Phrasea/Databox/Record/RecordRepository.php @@ -9,6 +9,8 @@ */ namespace Alchemy\Phrasea\Databox\Record; +use Alchemy\Phrasea\Model\Entities\User; + interface RecordRepository { /** @@ -35,4 +37,23 @@ interface RecordRepository * @return \record_adapter[] */ public function findByRecordIds(array $recordIds); + + /** + * Find children of each given storyId reachable for given user + * + * @param int[] $storyIds + * @param null|int|User $user + * @return \set_selection[] + */ + public function findChildren(array $storyIds, $user = null); + + + /** + * Find stories containing records + * + * @param int[] $recordIds + * @param null|int|User $user + * @return \set_selection[] + */ + public function findParents(array $recordIds, $user = null); } diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 2cbbee4466..628a1fab05 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1549,54 +1549,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface throw new Exception('This record is not a grouping'); } - if ($this->app->getAuthenticatedUser()) { - $sql = "SELECT record_id\n" - . " FROM regroup g\n" - . " INNER JOIN\n" - . " (record r INNER JOIN collusr c\n" - . " ON site = :site\n" - . " AND usr_id = :usr_id\n" - . " AND c.coll_id = r.coll_id\n" - . " AND ((status ^ mask_xor) & mask_and) = 0\n" - . " AND r.parent_record_id=0\n" - . " )\n" - . " ON (g.rid_child = r.record_id AND g.rid_parent = :record_id)\n" - . " ORDER BY g.ord ASC, dateadd ASC, record_id ASC"; + $selections = $this->getDatabox()->getRecordRepository()->findChildren([$this->getRecordId()]); - $params = [ - ':site' => $this->app['conf']->get(['main', 'key']), - ':usr_id' => $this->app->getAuthenticatedUser()->getId(), - ':record_id' => $this->getRecordId(), - ]; - } else { - $sql = "SELECT record_id\n" - . " FROM regroup g INNER JOIN record r\n" - . " ON (g.rid_child = r.record_id AND g.rid_parent = :record_id)\n" - . " ORDER BY g.ord ASC, dateadd ASC, record_id ASC"; - - $params = [ - ':record_id' => $this->getRecordId(), - ]; - } - - $recordIds = $this->getDataboxConnection()->fetchAll($sql, $params); - - $recordIds = array_map(function (array $row) { - return $row['record_id']; - }, $recordIds); - - $recordRepository = $this->getDatabox()->getRecordRepository(); - $records = $recordRepository->findByRecordIds($recordIds); - - $set = new set_selection($this->app); - $i = 1; - - foreach ($records as $record) { - $record->setNumber($i++); - $set->add_element($record); - } - - return $set; + return reset($selections); } /** @@ -1604,34 +1559,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface */ public function get_grouping_parents() { - $sql = "SELECT r.record_id\n" - . " FROM regroup g\n" - . " INNER JOIN\n" - . " (record r INNER JOIN collusr c\n" - . " ON site = :site\n" - . " AND usr_id = :usr_id\n" - . " AND c.coll_id = r.coll_id\n" - . " AND ((status ^ mask_xor) & mask_and)=0\n" - . " AND r.parent_record_id = 1\n" - . " )\n" - . " ON (g.rid_parent = r.record_id)\n" - . " WHERE rid_child = :record_id"; + $selections = $this->getDatabox()->getRecordRepository()->findParents([$this->getRecordId()]); - $stmt = $this->getDataboxConnection()->prepare($sql); - $stmt->execute([ - ':site' => $this->app['conf']->get(['main', 'key']), - ':usr_id' => $this->app->getAuthenticatedUser()->getId(), - ':record_id' => $this->getRecordId(), - ]); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - $set = new set_selection($this->app); - foreach ($rs as $row) { - $set->add_element(new record_adapter($this->app, $this->getDataboxId(), $row['record_id'])); - } - - return $set; + return reset($selections); } public function hasChild(\record_adapter $record)