Refactor getChildren() and get_grouping_parents()

This commit is contained in:
Benoît Burnichon
2016-05-11 15:05:39 +02:00
parent ea9458da77
commit 8e693964df
4 changed files with 180 additions and 97 deletions

View File

@@ -168,7 +168,7 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
}); });
$app['repo.records.factory'] = $app->protect(function (\databox $databox) use ($app) { $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) { $app['repo.collection-references'] = $app->share(function (PhraseaApplication $app) {

View File

@@ -11,19 +11,32 @@ namespace Alchemy\Phrasea\Databox\Record;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Cache\Exception; use Alchemy\Phrasea\Cache\Exception;
use Alchemy\Phrasea\Model\Entities\User;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Query\QueryBuilder;
class LegacyRecordRepository implements RecordRepository class LegacyRecordRepository implements RecordRepository
{ {
/** @var Application */ /**
* @var Application
*/
private $app; private $app;
/** @var \databox */
/**
* @var \databox
*/
private $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->app = $app;
$this->databox = $databox; $this->databox = $databox;
$this->site = $site;
} }
public function find($record_id, $number = null) public function find($record_id, $number = null)
@@ -107,30 +120,124 @@ class LegacyRecordRepository implements RecordRepository
return $this->mapRecordsFromResultSet($result); 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() private function createSelectBuilder()
{ {
$connection = $this->databox->get_connection(); return $this->databox->get_connection()->createQueryBuilder()
->select($this->getRecordSelects())
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'
)
->from('record', 'r'); ->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 * @param array $result
* @return \record_adapter[] * @return \record_adapter[]
@@ -139,8 +246,8 @@ class LegacyRecordRepository implements RecordRepository
{ {
$records = []; $records = [];
foreach ($result as $row) { foreach ($result as $index => $row) {
$records[] = $this->mapRecordFromResultRow($row); $records[$index] = $this->mapRecordFromResultRow($row);
} }
return $records; return $records;
@@ -162,4 +269,29 @@ class LegacyRecordRepository implements RecordRepository
return $record; 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);
}
} }

View File

@@ -9,6 +9,8 @@
*/ */
namespace Alchemy\Phrasea\Databox\Record; namespace Alchemy\Phrasea\Databox\Record;
use Alchemy\Phrasea\Model\Entities\User;
interface RecordRepository interface RecordRepository
{ {
/** /**
@@ -35,4 +37,23 @@ interface RecordRepository
* @return \record_adapter[] * @return \record_adapter[]
*/ */
public function findByRecordIds(array $recordIds); 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);
} }

View File

@@ -1549,54 +1549,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
throw new Exception('This record is not a grouping'); throw new Exception('This record is not a grouping');
} }
if ($this->app->getAuthenticatedUser()) { $selections = $this->getDatabox()->getRecordRepository()->findChildren([$this->getRecordId()]);
$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";
$params = [ return reset($selections);
':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;
} }
/** /**
@@ -1604,34 +1559,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
*/ */
public function get_grouping_parents() public function get_grouping_parents()
{ {
$sql = "SELECT r.record_id\n" $selections = $this->getDatabox()->getRecordRepository()->findParents([$this->getRecordId()]);
. " 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";
$stmt = $this->getDataboxConnection()->prepare($sql); return reset($selections);
$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;
} }
public function hasChild(\record_adapter $record) public function hasChild(\record_adapter $record)