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

IBX-2000: Added URL Wildcard Query with Criterion and Sort #301

Merged
merged 13 commits into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from 12 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
8 changes: 8 additions & 0 deletions eZ/Publish/API/Repository/URLWildcardService.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use eZ\Publish\API\Repository\Values\Content\URLWildcard;
use eZ\Publish\API\Repository\Values\Content\URLWildcardTranslationResult;
use eZ\Publish\API\Repository\Values\Content\URLWildcardUpdateStruct;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\SearchResult;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\URLWildcardQuery;

/**
* URLAlias service.
Expand Down Expand Up @@ -84,6 +86,12 @@ public function load(int $id): UrlWildcard;
*/
public function loadAll(int $offset = 0, int $limit = -1): iterable;

/**
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
public function findUrlWildcards(URLWildcardQuery $query): SearchResult;

/**
* Translates an url to an existing uri resource based on the
* source/destination patterns of the url wildcard.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use InvalidArgumentException;
use Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException;

/**
* Note that the class should ideally have been in a Logical namespace, but it would have then be named 'And',
Expand All @@ -30,26 +30,15 @@ abstract class LogicalOperator extends Criterion
*
* @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion[] $criteria
*
* @throws \InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
*/
public function __construct(array $criteria)
{
foreach ($criteria as $key => $criterion) {
if (!$criterion instanceof Criterion) {
if ($criterion === null) {
$type = 'null';
} elseif (is_object($criterion)) {
$type = get_class($criterion);
} elseif (is_array($criterion)) {
$type = 'Array, with keys: ' . implode(', ', array_keys($criterion));
} else {
$type = gettype($criterion) . ", with value: '{$criterion}'";
}

throw new InvalidArgumentException(
"You provided {$type} at index '{$key}', but only Criterion objects are accepted"
);
throw new InvalidCriterionArgumentException($key, $criterion, Criterion::class);
}

$this->criteria[] = $criterion;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace eZ\Publish\API\Repository\Values\URL\Query\Criterion;

use eZ\Publish\API\Repository\Values\URL\Query\Criterion;
use InvalidArgumentException;
use Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException;

abstract class LogicalOperator extends Criterion
{
Expand All @@ -25,25 +25,13 @@ abstract class LogicalOperator extends Criterion
*
* @param \eZ\Publish\API\Repository\Values\URL\Query\Criterion[] $criteria
*
* @throws \InvalidArgumentException
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\InvalidCriterionArgumentException
*/
public function __construct(array $criteria)
{
foreach ($criteria as $key => $criterion) {
if (!$criterion instanceof Criterion) {
if ($criterion === null) {
$type = 'null';
} elseif (is_object($criterion)) {
$type = get_class($criterion);
} elseif (is_array($criterion)) {
$type = 'Array, with keys: ' . implode(', ', array_keys($criterion));
} else {
$type = gettype($criterion) . ", with value: '{$criterion}'";
}

throw new InvalidArgumentException(
"You provided {$type} at index '{$key}', but only Criterion objects are accepted"
);
throw new InvalidCriterionArgumentException($key, $criterion, Criterion::class);
}

$this->criteria[] = $criterion;
Expand Down
11 changes: 11 additions & 0 deletions eZ/Publish/Core/Persistence/Cache/UrlWildcardHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard\Handler as UrlWildcardHandlerInterface;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\URLWildcardQuery;

class UrlWildcardHandler extends AbstractHandler implements UrlWildcardHandlerInterface
{
Expand Down Expand Up @@ -132,6 +133,16 @@ public function loadAll($offset = 0, $limit = -1)
return $this->persistenceHandler->urlWildcardHandler()->loadAll($offset, $limit);
}

/**
* @see \eZ\Publish\SPI\Persistence\Content\UrlWildcard\Handler::find
*/
public function find(URLWildcardQuery $query): array
{
$this->logger->logCall(__METHOD__, ['query' => $query]);

return $this->persistenceHandler->urlWildcardHandler()->find($query);
}

/**
* @see \eZ\Publish\SPI\Persistence\Content\UrlWildcard\Handler::lookup
*/
Expand Down
20 changes: 20 additions & 0 deletions eZ/Publish/Core/Persistence/Legacy/Content/UrlWildcard/Gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace eZ\Publish\Core\Persistence\Legacy\Content\UrlWildcard;

use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\Query\Criterion;

/**
* UrlWildcard Gateway.
Expand Down Expand Up @@ -50,6 +51,25 @@ abstract public function loadUrlWildcardData(int $id): array;
*/
abstract public function loadUrlWildcardsData(int $offset = 0, int $limit = -1): array;

/**
* Selects URLWildcards matching specified criteria.
*
* @return array{
* "rows": mixed,
* "count": int|null,
* }
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
* @throws \eZ\Publish\API\Repository\Exceptions\NotImplementedException if Criterion is not applicable to its target
*/
abstract public function find(
Criterion $criterion,
int $offset,
int $limit,
array $sortClauses = [],
bool $doCount = true
): array;

/**
* Load the UrlWildcard by source url $sourceUrl.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Query\QueryBuilder;
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
use eZ\Publish\Core\Persistence\Legacy\Content\UrlWildcard\Gateway;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\Query\Criterion;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\Query\SortClause;
use Ibexa\Core\Persistence\Legacy\Content\URLWildcard\Query\CriteriaConverter;
use RuntimeException;

/**
* URL wildcard gateway implementation using the Doctrine database.
Expand All @@ -33,9 +38,18 @@ final class DoctrineDatabase extends Gateway
/** @var \Doctrine\DBAL\Connection */
private $connection;

public function __construct(Connection $connection)
/** @var \Ibexa\Core\Persistence\Legacy\Content\URLWildcard\Query\CriteriaConverter */
protected $criteriaConverter;

public const SORT_DIRECTION_MAP = [
SortClause::SORT_ASC => 'ASC',
SortClause::SORT_DESC => 'DESC',
];

public function __construct(Connection $connection, CriteriaConverter $criteriaConverter)
{
$this->connection = $connection;
$this->criteriaConverter = $criteriaConverter;
}

public function insertUrlWildcard(UrlWildcard $urlWildcard): int
Expand Down Expand Up @@ -159,6 +173,42 @@ public function loadUrlWildcardsData(int $offset = 0, int $limit = -1): array
return $stmt->fetchAll(FetchMode::ASSOCIATIVE);
}

public function find(Criterion $criterion, int $offset, int $limit, array $sortClauses = [], bool $doCount = true): array
{
$count = $doCount ? $this->doCount($criterion) : null;
if (!$doCount && $limit === 0) {
throw new RuntimeException('Invalid query. Cannot disable count and request 0 items at the same time');
}

if ($limit === 0 || ($count !== null && $count <= $offset)) {
return [
'count' => $count,
'rows' => [],
];
}

if ($limit < 0) {
throw new InvalidArgumentException('$limit', 'The limit need be higher than 0');
}

$query = $this->buildLoadUrlWildcardDataQuery();
$query
->where($this->criteriaConverter->convertCriteria($query, $criterion))
->setMaxResults($limit)
->setFirstResult($offset);

foreach ($sortClauses as $sortClause) {
$query->addOrderBy($sortClause->target, $this->getQuerySortingDirection($sortClause->direction));
}

$statement = $query->execute();

return [
'count' => $count,
'rows' => $statement->fetchAllAssociative(),
];
}

public function loadUrlWildcardBySourceUrl(string $sourceUrl): array
{
$query = $this->buildLoadUrlWildcardDataQuery();
Expand Down Expand Up @@ -186,6 +236,44 @@ public function countAll(): int
return (int) $query->execute()->fetchColumn();
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\Query\Criterion $criterion
*
* @return int
*
* @throws \Doctrine\DBAL\Driver\Exception
* @throws \Doctrine\DBAL\Exception
* @throws \eZ\Publish\API\Repository\Exceptions\NotImplementedException
*/
protected function doCount(Criterion $criterion): int
{
$query = $this->connection->createQueryBuilder();
$query
->select($this->connection->getDatabasePlatform()->getCountExpression('url_wildcard.id'))
->from(self::URL_WILDCARD_TABLE, 'url_wildcard')
->where($this->criteriaConverter->convertCriteria($query, $criterion));

return (int)$query->execute()->fetchOne();
}

/**
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*/
private function getQuerySortingDirection(string $direction): string
{
if (!isset(self::SORT_DIRECTION_MAP[$direction])) {
throw new InvalidArgumentException(
'$sortClause->direction',
sprintf(
'Unsupported "%s" sorting direction, use one of the SortClause::SORT_* constants instead',
$direction
)
);
}

return self::SORT_DIRECTION_MAP[$direction];
}

private function trimUrl(string $url): string
{
return trim($url, '/');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use eZ\Publish\Core\Base\Exceptions\DatabaseException;
use eZ\Publish\Core\Persistence\Legacy\Content\UrlWildcard\Gateway;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\Query\Criterion;
use PDOException;

/**
Expand Down Expand Up @@ -90,6 +91,15 @@ public function loadUrlWildcardsData(int $offset = 0, int $limit = -1): array
}
}

public function find(Criterion $criterion, int $offset, int $limit, array $sortClauses = [], bool $doCount = true): array
{
try {
return $this->innerGateway->find($criterion, $offset, $limit, $sortClauses, $doCount);
} catch (DBALException | PDOException $e) {
throw DatabaseException::wrap($e);
}
}

public function loadUrlWildcardBySourceUrl(string $sourceUrl): array
{
try {
Expand Down
17 changes: 17 additions & 0 deletions eZ/Publish/Core/Persistence/Legacy/Content/UrlWildcard/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard\Handler as BaseUrlWildcardHandler;
use Ibexa\Contracts\Core\Repository\Values\Content\URLWildcard\URLWildcardQuery;

/**
* The UrlWildcard Handler provides nice urls with wildcards management.
Expand Down Expand Up @@ -139,6 +140,22 @@ public function loadAll($offset = 0, $limit = -1)
);
}

public function find(URLWildcardQuery $query): array
{
$results = $this->gateway->find(
$query->filter,
$query->offset,
$query->limit,
$query->sortClauses,
$query->performCount
);

return [
'count' => $results['count'],
'items' => $this->mapper->extractUrlWildcardsFromRows($results['rows']),
];
}

/**
* Performs lookup for given URL.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use eZ\Publish\Core\Persistence\Legacy\Content\UrlWildcard\Gateway\DoctrineDatabase;
use eZ\Publish\Core\Persistence\Legacy\Tests\TestCase;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use Ibexa\Core\Persistence\Legacy\Content\URLWildcard\Query\CriteriaConverter;
use Ibexa\Core\Persistence\Legacy\Content\URLWildcard\Query\CriterionHandler\MatchAll;

/**
* Test case for eZ\Publish\Core\Persistence\Legacy\Content\UrlWildcard\Gateway\DoctrineDatabase.
Expand Down Expand Up @@ -178,7 +180,8 @@ public function testDeleteUrlWildcard()
protected function getGateway(): DoctrineDatabase
{
if (!isset($this->gateway)) {
$this->gateway = new DoctrineDatabase($this->getDatabaseConnection());
$criteriaConverter = new CriteriaConverter([new MatchAll()]);
$this->gateway = new DoctrineDatabase($this->getDatabaseConnection(), $criteriaConverter);
}

return $this->gateway;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use eZ\Publish\Core\Persistence\Legacy\Content\UrlWildcard\Mapper;
use eZ\Publish\Core\Persistence\Legacy\Tests\TestCase;
use eZ\Publish\SPI\Persistence\Content\UrlWildcard;
use Ibexa\Core\Persistence\Legacy\Content\URLWildcard\Query\CriteriaConverter;
use Ibexa\Core\Persistence\Legacy\Content\URLWildcard\Query\CriterionHandler\MatchAll;

/**
* Test case for UrlWildcard Handler.
Expand Down Expand Up @@ -245,7 +247,8 @@ public function testLoadAllWithOffsetAndLimit()
protected function getHandler(): UrlWildcard\Handler
{
if (!isset($this->urlWildcardHandler)) {
$this->gateway = new DoctrineDatabase($this->getDatabaseConnection());
$criteriaConverter = new CriteriaConverter([new MatchAll()]);
$this->gateway = new DoctrineDatabase($this->getDatabaseConnection(), $criteriaConverter);
$this->mapper = new Mapper();

$this->urlWildcardHandler = new Handler(
Expand Down
Loading