diff --git a/module/Core/src/Repository/TagRepository.php b/module/Core/src/Repository/TagRepository.php index de304441..12db94fc 100644 --- a/module/Core/src/Repository/TagRepository.php +++ b/module/Core/src/Repository/TagRepository.php @@ -8,6 +8,7 @@ use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepository; use Happyr\DoctrineSpecification\Spec; use Shlinkio\Shlink\Core\Entity\Tag; use Shlinkio\Shlink\Core\Tag\Model\TagInfo; +use Shlinkio\Shlink\Core\Tag\Model\TagsListFiltering; use Shlinkio\Shlink\Core\Tag\Spec\CountTagsWithName; use Shlinkio\Shlink\Rest\ApiKey\Spec\WithApiKeySpecsEnsuringJoin; use Shlinkio\Shlink\Rest\Entity\ApiKey; @@ -32,29 +33,24 @@ class TagRepository extends EntitySpecificationRepository implements TagReposito /** * @return TagInfo[] */ - public function findTagsWithInfo( - ?int $limit = null, - ?int $offset = null, - ?string $searchTerm = null, - ?ApiKey $apiKey = null, - ): array { + public function findTagsWithInfo(?TagsListFiltering $filtering = null): array + { $qb = $this->createQueryBuilder('t'); $qb->select('t AS tag', 'COUNT(DISTINCT s.id) AS shortUrlsCount', 'COUNT(DISTINCT v.id) AS visitsCount') ->leftJoin('t.shortUrls', 's') ->leftJoin('s.visits', 'v') ->groupBy('t') ->orderBy('t.name', 'ASC') - ->setMaxResults($limit) - ->setFirstResult($offset); + ->setMaxResults($filtering?->limit()) + ->setFirstResult($filtering?->offset()); + $apiKey = $filtering?->apiKey(); if ($apiKey !== null) { $this->applySpecification($qb, $apiKey->spec(false, 'shortUrls'), 't'); } - $query = $qb->getQuery(); - return map( - $query->getResult(), + $qb->getQuery()->getResult(), static fn (array $row) => new TagInfo($row['tag'], (int) $row['shortUrlsCount'], (int) $row['visitsCount']), ); } diff --git a/module/Core/src/Repository/TagRepositoryInterface.php b/module/Core/src/Repository/TagRepositoryInterface.php index 0158d43d..9cbea269 100644 --- a/module/Core/src/Repository/TagRepositoryInterface.php +++ b/module/Core/src/Repository/TagRepositoryInterface.php @@ -7,6 +7,7 @@ namespace Shlinkio\Shlink\Core\Repository; use Doctrine\Persistence\ObjectRepository; use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryInterface; use Shlinkio\Shlink\Core\Tag\Model\TagInfo; +use Shlinkio\Shlink\Core\Tag\Model\TagsListFiltering; use Shlinkio\Shlink\Rest\Entity\ApiKey; interface TagRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface @@ -16,12 +17,7 @@ interface TagRepositoryInterface extends ObjectRepository, EntitySpecificationRe /** * @return TagInfo[] */ - public function findTagsWithInfo( - ?int $limit = null, - ?int $offset = null, - ?string $searchTerm = null, - ?ApiKey $apiKey = null, - ): array; + public function findTagsWithInfo(?TagsListFiltering $filtering = null): array; public function tagExists(string $tag, ?ApiKey $apiKey = null): bool; } diff --git a/module/Core/src/Tag/Model/TagsListFiltering.php b/module/Core/src/Tag/Model/TagsListFiltering.php new file mode 100644 index 00000000..3c4e79d2 --- /dev/null +++ b/module/Core/src/Tag/Model/TagsListFiltering.php @@ -0,0 +1,38 @@ +limit; + } + + public function offset(): ?int + { + return $this->offset; + } + + public function searchTerm(): ?string + { + return $this->searchTerm; + } + + public function apiKey(): ?ApiKey + { + return $this->apiKey; + } +} diff --git a/module/Core/src/Tag/Paginator/Adapter/TagsInfoPaginatorAdapter.php b/module/Core/src/Tag/Paginator/Adapter/TagsInfoPaginatorAdapter.php index 8d64942d..a92a190a 100644 --- a/module/Core/src/Tag/Paginator/Adapter/TagsInfoPaginatorAdapter.php +++ b/module/Core/src/Tag/Paginator/Adapter/TagsInfoPaginatorAdapter.php @@ -4,10 +4,14 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Core\Tag\Paginator\Adapter; +use Shlinkio\Shlink\Core\Tag\Model\TagsListFiltering; + class TagsInfoPaginatorAdapter extends AbstractTagsPaginatorAdapter { public function getSlice(int $offset, int $length): iterable { - return $this->repo->findTagsWithInfo($length, $offset, null, $this->apiKey); + return $this->repo->findTagsWithInfo( + new TagsListFiltering($length, $offset, $this->params->searchTerm(), $this->apiKey), + ); } } diff --git a/module/Core/test-db/Repository/TagRepositoryTest.php b/module/Core/test-db/Repository/TagRepositoryTest.php index 92498d9a..4c6fc3da 100644 --- a/module/Core/test-db/Repository/TagRepositoryTest.php +++ b/module/Core/test-db/Repository/TagRepositoryTest.php @@ -74,7 +74,7 @@ class TagRepositoryTest extends DatabaseTestCase $this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl2, Visitor::emptyInstance())); $this->getEntityManager()->flush(); - $result = $this->repo->findTagsWithInfo(); + $result = $this->repo->findTagsWithInfo(); // TODO Test with some filters self::assertCount(4, $result); self::assertEquals(0, $result[0]->shortUrlsCount()); diff --git a/module/Core/test/Service/Tag/TagServiceTest.php b/module/Core/test/Service/Tag/TagServiceTest.php index eac7495a..40d50b36 100644 --- a/module/Core/test/Service/Tag/TagServiceTest.php +++ b/module/Core/test/Service/Tag/TagServiceTest.php @@ -16,6 +16,7 @@ use Shlinkio\Shlink\Core\Exception\TagNotFoundException; use Shlinkio\Shlink\Core\Repository\TagRepository; use Shlinkio\Shlink\Core\Tag\Model\TagInfo; use Shlinkio\Shlink\Core\Tag\Model\TagRenaming; +use Shlinkio\Shlink\Core\Tag\Model\TagsListFiltering; use Shlinkio\Shlink\Core\Tag\Model\TagsParams; use Shlinkio\Shlink\Core\Tag\TagService; use Shlinkio\Shlink\Rest\ApiKey\Model\ApiKeyMeta; @@ -64,7 +65,7 @@ class TagServiceTest extends TestCase { $expected = [new TagInfo(new Tag('foo'), 1, 1), new TagInfo(new Tag('bar'), 3, 10)]; - $find = $this->repo->findTagsWithInfo(2, 0, null, $apiKey)->willReturn($expected); + $find = $this->repo->findTagsWithInfo(new TagsListFiltering(2, 0, null, $apiKey))->willReturn($expected); $count = $this->repo->matchSingleScalarResult(Argument::cetera())->willReturn(2); $result = $this->service->tagsInfo(TagsParams::fromRawData([]), $apiKey); // TODO Add more cases with params