mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-22 17:06:41 -06:00
Created DB-level paginator for tags with stats
This commit is contained in:
parent
3dd4e33758
commit
4b90cf93d3
@ -32,14 +32,20 @@ class TagRepository extends EntitySpecificationRepository implements TagReposito
|
||||
/**
|
||||
* @return TagInfo[]
|
||||
*/
|
||||
public function findTagsWithInfo(?ApiKey $apiKey = null): array
|
||||
{
|
||||
public function findTagsWithInfo(
|
||||
?int $limit = null,
|
||||
?int $offset = null,
|
||||
?string $searchTerm = null,
|
||||
?ApiKey $apiKey = 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');
|
||||
->orderBy('t.name', 'ASC')
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($offset);
|
||||
|
||||
if ($apiKey !== null) {
|
||||
$this->applySpecification($qb, $apiKey->spec(false, 'shortUrls'), 't');
|
||||
|
@ -16,7 +16,12 @@ interface TagRepositoryInterface extends ObjectRepository, EntitySpecificationRe
|
||||
/**
|
||||
* @return TagInfo[]
|
||||
*/
|
||||
public function findTagsWithInfo(?ApiKey $apiKey = null): array;
|
||||
public function findTagsWithInfo(
|
||||
?int $limit = null,
|
||||
?int $offset = null,
|
||||
?string $searchTerm = null,
|
||||
?ApiKey $apiKey = null,
|
||||
): array;
|
||||
|
||||
public function tagExists(string $tag, ?ApiKey $apiKey = null): bool;
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ abstract class AbstractTagsPaginatorAdapter implements AdapterInterface
|
||||
public function getNbResults(): int
|
||||
{
|
||||
return (int) $this->repo->matchSingleScalarResult(Spec::andX(
|
||||
// FIXME I don't think using Spec::selectNew is the correct thing here,
|
||||
// but seems to be the only way to use Spec::COUNT
|
||||
// FIXME I don't think using Spec::selectNew is the correct thing here, ideally it should be Spec::select,
|
||||
// but seems to be the only way to use Spec::COUNT(...)
|
||||
Spec::selectNew(Tag::class, Spec::COUNT('id', true)),
|
||||
new WithApiKeySpecsEnsuringJoin($this->apiKey),
|
||||
));
|
||||
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Tag\Paginator\Adapter;
|
||||
|
||||
class TagsInfoPaginatorAdapter extends AbstractTagsPaginatorAdapter
|
||||
{
|
||||
public function getSlice(int $offset, int $length): iterable
|
||||
{
|
||||
return $this->repo->findTagsWithInfo($length, $offset, null, $this->apiKey);
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ namespace Shlinkio\Shlink\Core\Tag;
|
||||
|
||||
use Doctrine\ORM;
|
||||
use Pagerfanta\Adapter\AdapterInterface;
|
||||
use Pagerfanta\Adapter\ArrayAdapter;
|
||||
use Shlinkio\Shlink\Common\Paginator\Paginator;
|
||||
use Shlinkio\Shlink\Core\Entity\Tag;
|
||||
use Shlinkio\Shlink\Core\Exception\ForbiddenTagOperationException;
|
||||
@ -17,6 +16,7 @@ use Shlinkio\Shlink\Core\Repository\TagRepositoryInterface;
|
||||
use Shlinkio\Shlink\Core\Tag\Model\TagInfo;
|
||||
use Shlinkio\Shlink\Core\Tag\Model\TagRenaming;
|
||||
use Shlinkio\Shlink\Core\Tag\Model\TagsParams;
|
||||
use Shlinkio\Shlink\Core\Tag\Paginator\Adapter\TagsInfoPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Tag\Paginator\Adapter\TagsPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
@ -43,9 +43,7 @@ class TagService implements TagServiceInterface
|
||||
{
|
||||
/** @var TagRepositoryInterface $repo */
|
||||
$repo = $this->em->getRepository(Tag::class);
|
||||
$tagsInfo = $repo->findTagsWithInfo($apiKey);
|
||||
|
||||
return $this->createPaginator(new ArrayAdapter($tagsInfo), $params);
|
||||
return $this->createPaginator(new TagsInfoPaginatorAdapter($repo, $params, $apiKey), $params);
|
||||
}
|
||||
|
||||
private function createPaginator(AdapterInterface $adapter, TagsParams $params): Paginator
|
||||
|
@ -47,7 +47,7 @@ class TagServiceTest extends TestCase
|
||||
$expected = [new Tag('foo'), new Tag('bar')];
|
||||
|
||||
$match = $this->repo->match(Argument::cetera())->willReturn($expected);
|
||||
$count = $this->repo->matchSingleScalarResult(Argument::cetera())->willReturn(0);
|
||||
$count = $this->repo->matchSingleScalarResult(Argument::cetera())->willReturn(2);
|
||||
|
||||
$result = $this->service->listTags(TagsParams::fromRawData([]));
|
||||
|
||||
@ -64,12 +64,14 @@ class TagServiceTest extends TestCase
|
||||
{
|
||||
$expected = [new TagInfo(new Tag('foo'), 1, 1), new TagInfo(new Tag('bar'), 3, 10)];
|
||||
|
||||
$find = $this->repo->findTagsWithInfo($apiKey)->willReturn($expected);
|
||||
$find = $this->repo->findTagsWithInfo(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
|
||||
|
||||
self::assertEquals($expected, $result->getCurrentPageResults());
|
||||
$find->shouldHaveBeenCalled();
|
||||
$count->shouldHaveBeenCalled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user