Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Feature/item persister and retriever #1112

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/MetaModels/DataAccess/DatabaseHelperTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/**
* This file is part of MetaModels/core.
*
* (c) 2012-2017 The MetaModels team.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* This project is provided in good faith and hope to be usable by anyone.
*
* @package MetaModels
* @subpackage Core
* @author Christian Schiffler <[email protected]>
* @copyright 2012-2017 The MetaModels team.
* @license https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0
* @filesource
*/

namespace MetaModels\DataAccess;

/**
* This trait provides some helper functions for database access.
*/
trait DatabaseHelperTrait
{
/**
* Build a list of the correct amount of "?" for use in a db query.
*
* @param array $parameters The parameters.
*
* @return string
*/
private function buildDatabaseParameterList(array $parameters)
{
return implode(',', array_fill(0, count($parameters), '?'));
}
}
340 changes: 340 additions & 0 deletions src/MetaModels/DataAccess/IdResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
<?php

/**
* This file is part of MetaModels/core.
*
* (c) 2012-2017 The MetaModels team.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* This project is provided in good faith and hope to be usable by anyone.
*
* @package MetaModels
* @subpackage Core
* @author Christian Schiffler <[email protected]>
* @copyright 2012-2017 The MetaModels team.
* @license https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0
* @filesource
*/

namespace MetaModels\DataAccess;

use Contao\Database;
use MetaModels\Filter\IFilter;
use MetaModels\IMetaModel;

/**
* This class resolves an id list.
*/
class IdResolver
{
use DatabaseHelperTrait;

/**
* The database.
*
* @var Database
*/
private $database;

/**
* The metamodel we work on.
*
* @var IMetaModel
*/
private $metaModel;

/**
* The MetaModel table name.
*
* @var string
*/
private $tableName;

/**
* The filter.
*
* @var IFilter
*/
private $filter;

/**
* The sort attribute.
*
* @var string
*/
private $sortBy;

/**
* The sort order.
*
* @var string
*/
private $sortOrder = 'ASC';

/**
* The offset.
*
* @var int
*/
private $offset = 0;

/**
* The limit.
*
* @var int
*/
private $limit = 0;

/**
* Create a new instance.
*
* @param IMetaModel $metaModel The MetaModel.
* @param Database $database The database.
*/
public function __construct(IMetaModel $metaModel, Database $database)
{
$this->database = $database;
$this->metaModel = $metaModel;
$this->tableName = $metaModel->getTableName();
}

/**
* Create a new instance.
*
* @param IMetaModel $metaModel The MetaModel.
* @param Database $database The database.
*
* @return IdResolver
*/
public static function create(IMetaModel $metaModel, Database $database)
{
return new static($metaModel, $database);
}

/**
* Retrieve filter.
*
* @return IFilter
*/
public function getFilter()
{
return $this->filter;
}

/**
* Set filter.
*
* @param IFilter $filter The new value.
*
* @return IdResolver
*/
public function setFilter(IFilter $filter = null)
{
$this->filter = $filter;

return $this;
}

/**
* Retrieve attribute.
*
* @return string
*/
public function getSortBy()
{
return $this->sortBy;
}

/**
* Set attribute.
*
* @param string $sortBy The new value.
*
* @return IdResolver
*/
public function setSortBy($sortBy)
{
$this->sortBy = (string) $sortBy;

return $this;
}

/**
* Retrieve sort order.
*
* @return string
*/
public function getSortOrder()
{
return $this->sortOrder;
}

/**
* Set sort order.
*
* @param string $sortOrder The new value.
*
* @return IdResolver
*/
public function setSortOrder($sortOrder)
{
$this->sortOrder = $sortOrder == 'DESC' ? 'DESC' : 'ASC';

return $this;
}

/**
* Retrieve offset.
*
* @return int
*/
public function getOffset()
{
return $this->offset;
}

/**
* Set offset.
*
* @param int $offset The new value.
*
* @return IdResolver
*/
public function setOffset($offset)
{
$this->offset = (int) $offset;

return $this;
}

/**
* Retrieve limit.
*
* @return int
*/
public function getLimit()
{
return $this->limit;
}

/**
* Set limit.
*
* @param int $limit The new value.
*
* @return IdResolver
*/
public function setLimit($limit)
{
$this->limit = (int) $limit;

return $this;
}

/**
* Retrieve the id list.
*
* @return string[]
*/
public function getIds()
{
if ([] === $filteredIds = array_filter($this->getMatchingIds())) {
return [];
}

// If desired, sort the entries.
if (!empty($filteredIds) && null !== $this->sortBy) {
$filteredIds = $this->sortIds($filteredIds);
}

// Apply limiting then.
if ($this->offset > 0 || $this->limit > 0) {
$filteredIds = array_slice($filteredIds, $this->offset, $this->limit ?: null);
}
return array_unique(array_filter($filteredIds));
}

/**
* Fetch the amount of matching items.
*
* @return int
*/
public function count()
{
$filteredIds = $this->getMatchingIds();
if (count($filteredIds) == 0) {
return 0;
}

$result = $this
->database
->prepare(sprintf(
'SELECT COUNT(id) AS count FROM %s WHERE id IN(%s)',
$this->tableName,
$this->buildDatabaseParameterList($filteredIds)
))
->execute($filteredIds);

return $result->count;
}

/**
* Narrow down the list of Ids that match the given filter.
*
* @return array all matching Ids.
*/
private function getMatchingIds()
{
if (null !== $this->filter && null !== ($matchingIds = $this->filter->getMatchingIds())) {
return $matchingIds;
}

// Either no filter object or all ids allowed => return all ids.
// if no id filter is passed, we assume all ids are provided.
$rows = $this->database->execute('SELECT id FROM ' . $this->tableName);

return $rows->fetchEach('id');
}

/**
* Sort the ids.
*
* @param string[] $filteredIds The id list.
*
* @return array
*/
private function sortIds($filteredIds)
{
switch (true) {
case ('random' === $this->sortBy):
shuffle($filteredIds);
return $filteredIds;
case 'id':
asort($filteredIds);
return $filteredIds;
case (null !== ($attribute = $this->metaModel->getAttribute($this->sortBy))):
return $attribute->sortIds($filteredIds, $this->sortOrder);
case (in_array($this->sortBy, ['pid', 'tstamp', 'sorting'])):
// Sort by database values.
return $this
->database
->prepare(
sprintf(
'SELECT id FROM %s WHERE id IN(%s) ORDER BY %s %s',
$this->tableName,
$this->buildDatabaseParameterList($filteredIds),
$this->sortBy,
$this->sortOrder
)
)
->execute($filteredIds)
->fetchEach('id');
default:
// Nothing we can do about this.
}

return $filteredIds;
}
}
Loading