mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-06 23:33:13 +08:00
Refactored ShortUrlRepository to wrap args into DTOs
This commit is contained in:
@@ -18,6 +18,11 @@ final class Ordering
|
||||
return new self($field, $dir ?? self::DEFAULT_DIR);
|
||||
}
|
||||
|
||||
public static function emptyInstance(): self
|
||||
{
|
||||
return self::fromTuple([null, null]);
|
||||
}
|
||||
|
||||
public function orderField(): ?string
|
||||
{
|
||||
return $this->field;
|
||||
|
||||
@@ -11,12 +11,13 @@ use Doctrine\ORM\QueryBuilder;
|
||||
use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepository;
|
||||
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||
use Shlinkio\Shlink\Core\Model\Ordering;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsListFiltering;
|
||||
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
|
||||
|
||||
use function array_column;
|
||||
@@ -26,27 +27,18 @@ use function Functional\contains;
|
||||
class ShortUrlRepository extends EntitySpecificationRepository implements ShortUrlRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @param string[] $tags
|
||||
* @return ShortUrl[]
|
||||
*/
|
||||
public function findList(
|
||||
?int $limit = null,
|
||||
?int $offset = null,
|
||||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?string $tagsMode = null,
|
||||
?Ordering $orderBy = null,
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null,
|
||||
): array {
|
||||
$qb = $this->createListQueryBuilder($searchTerm, $tags, $tagsMode, $dateRange, $spec);
|
||||
public function findList(ShortUrlsListFiltering $filtering): array
|
||||
{
|
||||
$qb = $this->createListQueryBuilder($filtering);
|
||||
$qb->select('DISTINCT s')
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($offset);
|
||||
->setMaxResults($filtering->limit())
|
||||
->setFirstResult($filtering->offset());
|
||||
|
||||
// In case the ordering has been specified, the query could be more complex. Process it
|
||||
if ($orderBy?->hasOrderField()) {
|
||||
return $this->processOrderByForList($qb, $orderBy);
|
||||
if ($filtering->orderBy()->hasOrderField()) {
|
||||
return $this->processOrderByForList($qb, $filtering->orderBy());
|
||||
}
|
||||
|
||||
// With no explicit order by, fallback to dateCreated-DESC
|
||||
@@ -77,30 +69,21 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
public function countList(
|
||||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?string $tagsMode = null,
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null,
|
||||
): int {
|
||||
$qb = $this->createListQueryBuilder($searchTerm, $tags, $tagsMode, $dateRange, $spec);
|
||||
public function countList(ShortUrlsCountFiltering $filtering): int
|
||||
{
|
||||
$qb = $this->createListQueryBuilder($filtering);
|
||||
$qb->select('COUNT(DISTINCT s)');
|
||||
|
||||
return (int) $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
private function createListQueryBuilder(
|
||||
?string $searchTerm,
|
||||
array $tags,
|
||||
?string $tagsMode,
|
||||
?DateRange $dateRange,
|
||||
?Specification $spec,
|
||||
): QueryBuilder {
|
||||
private function createListQueryBuilder(ShortUrlsCountFiltering $filtering): QueryBuilder
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
$qb->from(ShortUrl::class, 's')
|
||||
->where('1=1');
|
||||
|
||||
$dateRange = $filtering->dateRange();
|
||||
if ($dateRange?->startDate() !== null) {
|
||||
$qb->andWhere($qb->expr()->gte('s.dateCreated', ':startDate'));
|
||||
$qb->setParameter('startDate', $dateRange->startDate(), ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
@@ -110,6 +93,8 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
||||
$qb->setParameter('endDate', $dateRange->endDate(), ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
}
|
||||
|
||||
$searchTerm = $filtering->searchTerm();
|
||||
$tags = $filtering->tags();
|
||||
// Apply search term to every searchable field if not empty
|
||||
if (! empty($searchTerm)) {
|
||||
// Left join with tags only if no tags were provided. In case of tags, an inner join will be done later
|
||||
@@ -131,13 +116,13 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
||||
|
||||
// Filter by tags if provided
|
||||
if (! empty($tags)) {
|
||||
$tagsMode = $tagsMode ?? ShortUrlsParams::TAGS_MODE_ANY;
|
||||
$tagsMode = $filtering->tagsMode() ?? ShortUrlsParams::TAGS_MODE_ANY;
|
||||
$tagsMode === ShortUrlsParams::TAGS_MODE_ANY
|
||||
? $qb->join('s.tags', 't')->andWhere($qb->expr()->in('t.name', $tags))
|
||||
: $this->joinAllTags($qb, $tags);
|
||||
}
|
||||
|
||||
$this->applySpecification($qb, $spec, 's');
|
||||
$this->applySpecification($qb, $filtering->apiKey()?->spec(), 's');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
@@ -7,34 +7,20 @@ namespace Shlinkio\Shlink\Core\Repository;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryInterface;
|
||||
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||
use Shlinkio\Shlink\Core\Model\Ordering;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsListFiltering;
|
||||
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
|
||||
|
||||
interface ShortUrlRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
|
||||
{
|
||||
public function findList(
|
||||
?int $limit = null,
|
||||
?int $offset = null,
|
||||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?string $tagsMode = null,
|
||||
?Ordering $orderBy = null,
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null,
|
||||
): array;
|
||||
public function findList(ShortUrlsListFiltering $filtering): array;
|
||||
|
||||
public function countList(
|
||||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?string $tagsMode = null,
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null,
|
||||
): int;
|
||||
public function countList(ShortUrlsCountFiltering $filtering): int;
|
||||
|
||||
// TODO Use ShortUrlIdentifier here
|
||||
public function findOneWithDomainFallback(string $shortCode, ?string $domain = null): ?ShortUrl;
|
||||
|
||||
public function findOne(ShortUrlIdentifier $identifier, ?Specification $spec = null): ?ShortUrl;
|
||||
|
||||
@@ -12,10 +12,10 @@ use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlEdit;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
|
||||
use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
|
||||
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelperInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Paginator\Adapter\ShortUrlRepositoryAdapter;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Resolver\ShortUrlRelationResolverInterface;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Paginator\Adapter;
|
||||
namespace Shlinkio\Shlink\Core\ShortUrl\Paginator\Adapter;
|
||||
|
||||
use Pagerfanta\Adapter\AdapterInterface;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsListFiltering;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class ShortUrlRepositoryAdapter implements AdapterInterface
|
||||
@@ -21,25 +23,12 @@ class ShortUrlRepositoryAdapter implements AdapterInterface
|
||||
public function getSlice(int $offset, int $length): iterable
|
||||
{
|
||||
return $this->repository->findList(
|
||||
$length,
|
||||
$offset,
|
||||
$this->params->searchTerm(),
|
||||
$this->params->tags(),
|
||||
$this->params->tagsMode(),
|
||||
$this->params->orderBy(),
|
||||
$this->params->dateRange(),
|
||||
$this->apiKey?->spec(),
|
||||
ShortUrlsListFiltering::fromLimitsAndParams($length, $offset, $this->params, $this->apiKey),
|
||||
);
|
||||
}
|
||||
|
||||
public function getNbResults(): int
|
||||
{
|
||||
return $this->repository->countList(
|
||||
$this->params->searchTerm(),
|
||||
$this->params->tags(),
|
||||
$this->params->tagsMode(),
|
||||
$this->params->dateRange(),
|
||||
$this->apiKey?->spec(),
|
||||
);
|
||||
return $this->repository->countList(ShortUrlsCountFiltering::fromParams($this->params, $this->apiKey));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\ShortUrl\Persistence;
|
||||
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class ShortUrlsCountFiltering
|
||||
{
|
||||
public function __construct(
|
||||
private ?string $searchTerm = null,
|
||||
private array $tags = [],
|
||||
private ?string $tagsMode = null,
|
||||
private ?DateRange $dateRange = null,
|
||||
private ?ApiKey $apiKey = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function fromParams(ShortUrlsParams $params, ?ApiKey $apiKey): self
|
||||
{
|
||||
return new self($params->searchTerm(), $params->tags(), $params->tagsMode(), $params->dateRange(), $apiKey);
|
||||
}
|
||||
|
||||
public function searchTerm(): ?string
|
||||
{
|
||||
return $this->searchTerm;
|
||||
}
|
||||
|
||||
public function tags(): array
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function tagsMode(): ?string
|
||||
{
|
||||
return $this->tagsMode;
|
||||
}
|
||||
|
||||
public function dateRange(): ?DateRange
|
||||
{
|
||||
return $this->dateRange;
|
||||
}
|
||||
|
||||
public function apiKey(): ?ApiKey
|
||||
{
|
||||
return $this->apiKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\ShortUrl\Persistence;
|
||||
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Model\Ordering;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class ShortUrlsListFiltering extends ShortUrlsCountFiltering
|
||||
{
|
||||
public function __construct(
|
||||
private ?int $limit,
|
||||
private ?int $offset,
|
||||
private Ordering $orderBy,
|
||||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?string $tagsMode = null,
|
||||
?DateRange $dateRange = null,
|
||||
?ApiKey $apiKey = null,
|
||||
) {
|
||||
parent::__construct($searchTerm, $tags, $tagsMode, $dateRange, $apiKey);
|
||||
}
|
||||
|
||||
public static function fromLimitsAndParams(int $limit, int $offset, ShortUrlsParams $params, ?ApiKey $apiKey): self
|
||||
{
|
||||
return new self(
|
||||
$limit,
|
||||
$offset,
|
||||
$params->orderBy(),
|
||||
$params->searchTerm(),
|
||||
$params->tags(),
|
||||
$params->tagsMode(),
|
||||
$params->dateRange(),
|
||||
$apiKey,
|
||||
);
|
||||
}
|
||||
|
||||
public function offset(): ?int
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
public function limit(): ?int
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
public function orderBy(): Ordering
|
||||
{
|
||||
return $this->orderBy;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user