mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-10 17:23:12 +08:00
Allow tags, orphan and non-orphan visits to be provided a domain filter param
This commit is contained in:
@@ -9,7 +9,7 @@ use Shlinkio\Shlink\Common\Paginator\Paginator;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -39,7 +39,7 @@ class GetTagVisitsCommand extends AbstractVisitsListCommand
|
||||
protected function getVisitsPaginator(InputInterface $input, DateRange $dateRange): Paginator
|
||||
{
|
||||
$tag = $input->getArgument('tag');
|
||||
return $this->visitsHelper->visitsForTag($tag, new VisitsParams($dateRange));
|
||||
return $this->visitsHelper->visitsForTag($tag, new WithDomainVisitsParams($dateRange));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ use Shlinkio\Shlink\Common\Paginator\Paginator;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
@@ -35,7 +35,7 @@ class GetNonOrphanVisitsCommand extends AbstractVisitsListCommand
|
||||
*/
|
||||
protected function getVisitsPaginator(InputInterface $input, DateRange $dateRange): Paginator
|
||||
{
|
||||
return $this->visitsHelper->nonOrphanVisits(new VisitsParams($dateRange));
|
||||
return $this->visitsHelper->nonOrphanVisits(new WithDomainVisitsParams($dateRange));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ use Shlinkio\Shlink\Common\Paginator\Paginator;
|
||||
|
||||
abstract class AbstractInfinitePaginableListParams
|
||||
{
|
||||
private const FIRST_PAGE = 1;
|
||||
private const int FIRST_PAGE = 1;
|
||||
|
||||
public readonly int $page;
|
||||
public readonly int $itemsPerPage;
|
||||
|
||||
@@ -9,20 +9,22 @@ use ValueError;
|
||||
use function Shlinkio\Shlink\Core\enumToString;
|
||||
use function sprintf;
|
||||
|
||||
final class OrphanVisitsParams extends VisitsParams
|
||||
final class OrphanVisitsParams extends WithDomainVisitsParams
|
||||
{
|
||||
public function __construct(
|
||||
DateRange|null $dateRange = null,
|
||||
int|null $page = null,
|
||||
int|null $itemsPerPage = null,
|
||||
bool $excludeBots = false,
|
||||
string|null $domain = null,
|
||||
public readonly OrphanVisitType|null $type = null,
|
||||
) {
|
||||
parent::__construct($dateRange, $page, $itemsPerPage, $excludeBots);
|
||||
parent::__construct($dateRange, $page, $itemsPerPage, $excludeBots, $domain);
|
||||
}
|
||||
|
||||
public static function fromVisitsParamsAndRawData(VisitsParams $visitsParams, array $query): self
|
||||
public static function fromRawData(array $query): self
|
||||
{
|
||||
$visitsParams = WithDomainVisitsParams::fromRawData($query);
|
||||
$type = $query['type'] ?? null;
|
||||
|
||||
return new self(
|
||||
@@ -30,6 +32,7 @@ final class OrphanVisitsParams extends VisitsParams
|
||||
page: $visitsParams->page,
|
||||
itemsPerPage: $visitsParams->itemsPerPage,
|
||||
excludeBots: $visitsParams->excludeBots,
|
||||
domain: $visitsParams->domain,
|
||||
type: $type !== null ? self::parseType($type) : null,
|
||||
);
|
||||
}
|
||||
|
||||
31
module/Core/src/Visit/Model/WithDomainVisitsParams.php
Normal file
31
module/Core/src/Visit/Model/WithDomainVisitsParams.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Visit\Model;
|
||||
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
|
||||
class WithDomainVisitsParams extends VisitsParams
|
||||
{
|
||||
public function __construct(
|
||||
DateRange|null $dateRange = null,
|
||||
int|null $page = null,
|
||||
int|null $itemsPerPage = null,
|
||||
bool $excludeBots = false,
|
||||
public readonly string|null $domain = null,
|
||||
) {
|
||||
parent::__construct($dateRange, $page, $itemsPerPage, $excludeBots);
|
||||
}
|
||||
|
||||
public static function fromRawData(array $query): self
|
||||
{
|
||||
$visitsParams = VisitsParams::fromRawData($query);
|
||||
|
||||
return new self(
|
||||
dateRange: $visitsParams->dateRange,
|
||||
page: $visitsParams->page,
|
||||
itemsPerPage: $visitsParams->itemsPerPage,
|
||||
excludeBots: $visitsParams->excludeBots,
|
||||
domain: $query['domain'] ?? null,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ namespace Shlinkio\Shlink\Core\Visit\Paginator\Adapter;
|
||||
|
||||
use Shlinkio\Shlink\Core\Paginator\Adapter\AbstractCacheableCountPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitRepositoryInterface;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
@@ -17,26 +17,28 @@ class NonOrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAda
|
||||
{
|
||||
public function __construct(
|
||||
private readonly VisitRepositoryInterface $repo,
|
||||
private readonly VisitsParams $params,
|
||||
private readonly WithDomainVisitsParams $params,
|
||||
private readonly ApiKey|null $apiKey,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function doCount(): int
|
||||
{
|
||||
return $this->repo->countNonOrphanVisits(new VisitsCountFiltering(
|
||||
return $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering(
|
||||
$this->params->dateRange,
|
||||
$this->params->excludeBots,
|
||||
$this->apiKey,
|
||||
$this->params->domain,
|
||||
));
|
||||
}
|
||||
|
||||
public function getSlice(int $offset, int $length): iterable
|
||||
{
|
||||
return $this->repo->findNonOrphanVisits(new VisitsListFiltering(
|
||||
return $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(
|
||||
$this->params->dateRange,
|
||||
$this->params->excludeBots,
|
||||
$this->apiKey,
|
||||
$this->params->domain,
|
||||
$length,
|
||||
$offset,
|
||||
));
|
||||
|
||||
@@ -28,6 +28,7 @@ class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
|
||||
dateRange: $this->params->dateRange,
|
||||
excludeBots: $this->params->excludeBots,
|
||||
apiKey: $this->apiKey,
|
||||
domain: $this->params->domain,
|
||||
type: $this->params->type,
|
||||
));
|
||||
}
|
||||
@@ -38,6 +39,7 @@ class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
|
||||
dateRange: $this->params->dateRange,
|
||||
excludeBots: $this->params->excludeBots,
|
||||
apiKey: $this->apiKey,
|
||||
domain: $this->params->domain,
|
||||
type: $this->params->type,
|
||||
limit: $length,
|
||||
offset: $offset,
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace Shlinkio\Shlink\Core\Visit\Paginator\Adapter;
|
||||
|
||||
use Shlinkio\Shlink\Core\Paginator\Adapter\AbstractCacheableCountPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitRepositoryInterface;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
@@ -18,7 +18,7 @@ class TagVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
|
||||
public function __construct(
|
||||
private readonly VisitRepositoryInterface $visitRepository,
|
||||
private readonly string $tag,
|
||||
private readonly VisitsParams $params,
|
||||
private readonly WithDomainVisitsParams $params,
|
||||
private readonly ApiKey|null $apiKey,
|
||||
) {
|
||||
}
|
||||
@@ -27,10 +27,11 @@ class TagVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
|
||||
{
|
||||
return $this->visitRepository->findVisitsByTag(
|
||||
$this->tag,
|
||||
new VisitsListFiltering(
|
||||
new WithDomainVisitsListFiltering(
|
||||
$this->params->dateRange,
|
||||
$this->params->excludeBots,
|
||||
$this->apiKey,
|
||||
$this->params->domain,
|
||||
$length,
|
||||
$offset,
|
||||
),
|
||||
@@ -41,10 +42,11 @@ class TagVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
|
||||
{
|
||||
return $this->visitRepository->countVisitsByTag(
|
||||
$this->tag,
|
||||
new VisitsCountFiltering(
|
||||
new WithDomainVisitsCountFiltering(
|
||||
$this->params->dateRange,
|
||||
$this->params->excludeBots,
|
||||
$this->apiKey,
|
||||
$this->params->domain,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,15 @@ use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\OrphanVisitType;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class OrphanVisitsCountFiltering extends VisitsCountFiltering
|
||||
class OrphanVisitsCountFiltering extends WithDomainVisitsCountFiltering
|
||||
{
|
||||
public function __construct(
|
||||
DateRange|null $dateRange = null,
|
||||
bool $excludeBots = false,
|
||||
ApiKey|null $apiKey = null,
|
||||
string|null $domain = null,
|
||||
public readonly OrphanVisitType|null $type = null,
|
||||
) {
|
||||
parent::__construct($dateRange, $excludeBots, $apiKey);
|
||||
parent::__construct($dateRange, $excludeBots, $apiKey, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@ final class OrphanVisitsListFiltering extends OrphanVisitsCountFiltering
|
||||
DateRange|null $dateRange = null,
|
||||
bool $excludeBots = false,
|
||||
ApiKey|null $apiKey = null,
|
||||
string|null $domain = null,
|
||||
OrphanVisitType|null $type = null,
|
||||
public readonly int|null $limit = null,
|
||||
public readonly int|null $offset = null,
|
||||
) {
|
||||
parent::__construct($dateRange, $excludeBots, $apiKey, $type);
|
||||
parent::__construct($dateRange, $excludeBots, $apiKey, $domain, $type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Visit\Persistence;
|
||||
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class WithDomainVisitsCountFiltering extends VisitsCountFiltering
|
||||
{
|
||||
public function __construct(
|
||||
DateRange|null $dateRange = null,
|
||||
bool $excludeBots = false,
|
||||
ApiKey|null $apiKey = null,
|
||||
public readonly string|null $domain = null,
|
||||
) {
|
||||
parent::__construct($dateRange, $excludeBots, $apiKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Visit\Persistence;
|
||||
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
final class WithDomainVisitsListFiltering extends WithDomainVisitsCountFiltering
|
||||
{
|
||||
public function __construct(
|
||||
DateRange|null $dateRange = null,
|
||||
bool $excludeBots = false,
|
||||
ApiKey|null $apiKey = null,
|
||||
string|null $domain = null,
|
||||
public readonly int|null $limit = null,
|
||||
public readonly int|null $offset = null,
|
||||
) {
|
||||
parent::__construct($dateRange, $excludeBots, $apiKey, $domain);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Spec\CountOfNonOrphanVisits;
|
||||
use Shlinkio\Shlink\Core\Visit\Spec\CountOfOrphanVisits;
|
||||
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
||||
@@ -69,7 +70,7 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function findVisitsByTag(string $tag, VisitsListFiltering $filtering): array
|
||||
public function findVisitsByTag(string $tag, WithDomainVisitsListFiltering $filtering): array
|
||||
{
|
||||
$qb = $this->createVisitsByTagQueryBuilder($tag, $filtering);
|
||||
return $this->resolveVisitsWithNativeQuery($qb, $filtering->limit, $filtering->offset);
|
||||
@@ -173,7 +174,7 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
||||
/**
|
||||
* @return Visit[]
|
||||
*/
|
||||
public function findNonOrphanVisits(VisitsListFiltering $filtering): array
|
||||
public function findNonOrphanVisits(WithDomainVisitsListFiltering $filtering): array
|
||||
{
|
||||
$qb = $this->createAllVisitsQueryBuilder($filtering);
|
||||
$qb->andWhere($qb->expr()->isNotNull('v.shortUrl'));
|
||||
@@ -193,8 +194,9 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
||||
return (int) $this->matchSingleScalarResult(new CountOfNonOrphanVisits($filtering));
|
||||
}
|
||||
|
||||
private function createAllVisitsQueryBuilder(VisitsListFiltering|OrphanVisitsListFiltering $filtering): QueryBuilder
|
||||
{
|
||||
private function createAllVisitsQueryBuilder(
|
||||
VisitsListFiltering|OrphanVisitsListFiltering|WithDomainVisitsListFiltering $filtering,
|
||||
): QueryBuilder {
|
||||
// Parameters in this query need to be inlined, not bound, as we need to use it as sub-query later
|
||||
// Since they are not provided by the caller, it's reasonably safe
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
|
||||
@@ -12,6 +12,8 @@ use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
|
||||
/**
|
||||
* @extends ObjectRepository<Visit>
|
||||
@@ -28,9 +30,9 @@ interface VisitRepositoryInterface extends ObjectRepository, EntitySpecification
|
||||
/**
|
||||
* @return Visit[]
|
||||
*/
|
||||
public function findVisitsByTag(string $tag, VisitsListFiltering $filtering): array;
|
||||
public function findVisitsByTag(string $tag, WithDomainVisitsListFiltering $filtering): array;
|
||||
|
||||
public function countVisitsByTag(string $tag, VisitsCountFiltering $filtering): int;
|
||||
public function countVisitsByTag(string $tag, WithDomainVisitsCountFiltering $filtering): int;
|
||||
|
||||
/**
|
||||
* @return Visit[]
|
||||
@@ -49,9 +51,9 @@ interface VisitRepositoryInterface extends ObjectRepository, EntitySpecification
|
||||
/**
|
||||
* @return Visit[]
|
||||
*/
|
||||
public function findNonOrphanVisits(VisitsListFiltering $filtering): array;
|
||||
public function findNonOrphanVisits(WithDomainVisitsListFiltering $filtering): array;
|
||||
|
||||
public function countNonOrphanVisits(VisitsCountFiltering $filtering): int;
|
||||
public function countNonOrphanVisits(WithDomainVisitsCountFiltering $filtering): int;
|
||||
|
||||
public function findMostRecentOrphanVisit(): Visit|null;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\OrphanVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Paginator\Adapter\DomainVisitsPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Visit\Paginator\Adapter\NonOrphanVisitsPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Visit\Paginator\Adapter\OrphanVisitsPaginatorAdapter;
|
||||
@@ -88,7 +89,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function visitsForTag(string $tag, VisitsParams $params, ApiKey|null $apiKey = null): Paginator
|
||||
public function visitsForTag(string $tag, WithDomainVisitsParams $params, ApiKey|null $apiKey = null): Paginator
|
||||
{
|
||||
/** @var TagRepository $tagRepo */
|
||||
$tagRepo = $this->em->getRepository(Tag::class);
|
||||
@@ -130,7 +131,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
|
||||
return $this->createPaginator(new OrphanVisitsPaginatorAdapter($repo, $params, $apiKey), $params);
|
||||
}
|
||||
|
||||
public function nonOrphanVisits(VisitsParams $params, ApiKey|null $apiKey = null): Paginator
|
||||
public function nonOrphanVisits(WithDomainVisitsParams $params, ApiKey|null $apiKey = null): Paginator
|
||||
{
|
||||
/** @var VisitRepository $repo */
|
||||
$repo = $this->em->getRepository(Visit::class);
|
||||
|
||||
@@ -13,6 +13,7 @@ use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\OrphanVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
interface VisitsStatsHelperInterface
|
||||
@@ -33,7 +34,7 @@ interface VisitsStatsHelperInterface
|
||||
* @return Paginator<Visit>
|
||||
* @throws TagNotFoundException
|
||||
*/
|
||||
public function visitsForTag(string $tag, VisitsParams $params, ApiKey|null $apiKey = null): Paginator;
|
||||
public function visitsForTag(string $tag, WithDomainVisitsParams $params, ApiKey|null $apiKey = null): Paginator;
|
||||
|
||||
/**
|
||||
* @return Paginator<Visit>
|
||||
@@ -49,5 +50,5 @@ interface VisitsStatsHelperInterface
|
||||
/**
|
||||
* @return Paginator<Visit>
|
||||
*/
|
||||
public function nonOrphanVisits(VisitsParams $params, ApiKey|null $apiKey = null): Paginator;
|
||||
public function nonOrphanVisits(WithDomainVisitsParams $params, ApiKey|null $apiKey = null): Paginator;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\OrphanVisitsCountRepository;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\ShortUrlVisitsCountRepository;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitRepository;
|
||||
@@ -187,13 +188,13 @@ class VisitRepositoryTest extends DatabaseTestCase
|
||||
$this->createShortUrlsAndVisits(false, [$foo]);
|
||||
$this->getEntityManager()->flush();
|
||||
|
||||
self::assertCount(0, $this->repo->findVisitsByTag('invalid', new VisitsListFiltering()));
|
||||
self::assertCount(18, $this->repo->findVisitsByTag($foo, new VisitsListFiltering()));
|
||||
self::assertCount(12, $this->repo->findVisitsByTag($foo, new VisitsListFiltering(null, true)));
|
||||
self::assertCount(6, $this->repo->findVisitsByTag($foo, new VisitsListFiltering(
|
||||
self::assertCount(0, $this->repo->findVisitsByTag('invalid', new WithDomainVisitsListFiltering()));
|
||||
self::assertCount(18, $this->repo->findVisitsByTag($foo, new WithDomainVisitsListFiltering()));
|
||||
self::assertCount(12, $this->repo->findVisitsByTag($foo, new WithDomainVisitsListFiltering(null, true)));
|
||||
self::assertCount(6, $this->repo->findVisitsByTag($foo, new WithDomainVisitsListFiltering(
|
||||
DateRange::between(Chronos::parse('2016-01-02'), Chronos::parse('2016-01-03')),
|
||||
)));
|
||||
self::assertCount(12, $this->repo->findVisitsByTag($foo, new VisitsListFiltering(
|
||||
self::assertCount(12, $this->repo->findVisitsByTag($foo, new WithDomainVisitsListFiltering(
|
||||
DateRange::since(Chronos::parse('2016-01-03')),
|
||||
)));
|
||||
}
|
||||
@@ -479,31 +480,38 @@ class VisitRepositoryTest extends DatabaseTestCase
|
||||
|
||||
$this->getEntityManager()->flush();
|
||||
|
||||
self::assertCount(21, $this->repo->findNonOrphanVisits(new VisitsListFiltering()));
|
||||
self::assertCount(21, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::allTime())));
|
||||
self::assertCount(4, $this->repo->findNonOrphanVisits(new VisitsListFiltering(apiKey: $authoredApiKey)));
|
||||
self::assertCount(7, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::since(
|
||||
self::assertCount(21, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering()));
|
||||
self::assertCount(21, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(
|
||||
DateRange::allTime(),
|
||||
)));
|
||||
self::assertCount(4, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(
|
||||
apiKey: $authoredApiKey,
|
||||
)));
|
||||
self::assertCount(7, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(DateRange::since(
|
||||
Chronos::parse('2016-01-05')->endOfDay(),
|
||||
))));
|
||||
self::assertCount(12, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::until(
|
||||
self::assertCount(12, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(DateRange::until(
|
||||
Chronos::parse('2016-01-04')->endOfDay(),
|
||||
))));
|
||||
self::assertCount(6, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::between(
|
||||
self::assertCount(6, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(DateRange::between(
|
||||
Chronos::parse('2016-01-03')->startOfDay(),
|
||||
Chronos::parse('2016-01-04')->endOfDay(),
|
||||
))));
|
||||
self::assertCount(13, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::between(
|
||||
self::assertCount(13, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(DateRange::between(
|
||||
Chronos::parse('2016-01-03')->startOfDay(),
|
||||
Chronos::parse('2016-01-08')->endOfDay(),
|
||||
))));
|
||||
self::assertCount(3, $this->repo->findNonOrphanVisits(new VisitsListFiltering(DateRange::between(
|
||||
self::assertCount(3, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(DateRange::between(
|
||||
Chronos::parse('2016-01-03')->startOfDay(),
|
||||
Chronos::parse('2016-01-08')->endOfDay(),
|
||||
), limit: 10, offset: 10)));
|
||||
self::assertCount(15, $this->repo->findNonOrphanVisits(new VisitsListFiltering(excludeBots: true)));
|
||||
self::assertCount(10, $this->repo->findNonOrphanVisits(new VisitsListFiltering(limit: 10)));
|
||||
self::assertCount(1, $this->repo->findNonOrphanVisits(new VisitsListFiltering(limit: 10, offset: 20)));
|
||||
self::assertCount(5, $this->repo->findNonOrphanVisits(new VisitsListFiltering(limit: 5, offset: 5)));
|
||||
self::assertCount(15, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(excludeBots: true)));
|
||||
self::assertCount(10, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(limit: 10)));
|
||||
self::assertCount(1, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(
|
||||
limit: 10,
|
||||
offset: 20,
|
||||
)));
|
||||
self::assertCount(5, $this->repo->findNonOrphanVisits(new WithDomainVisitsListFiltering(limit: 5, offset: 5)));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
|
||||
@@ -10,10 +10,10 @@ use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\Visitor;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Paginator\Adapter\NonOrphanVisitsPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitRepositoryInterface;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
@@ -21,13 +21,13 @@ class NonOrphanVisitsPaginatorAdapterTest extends TestCase
|
||||
{
|
||||
private NonOrphanVisitsPaginatorAdapter $adapter;
|
||||
private MockObject & VisitRepositoryInterface $repo;
|
||||
private VisitsParams $params;
|
||||
private WithDomainVisitsParams $params;
|
||||
private ApiKey $apiKey;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->repo = $this->createMock(VisitRepositoryInterface::class);
|
||||
$this->params = VisitsParams::fromRawData([]);
|
||||
$this->params = WithDomainVisitsParams::fromRawData([]);
|
||||
$this->apiKey = ApiKey::create();
|
||||
|
||||
$this->adapter = new NonOrphanVisitsPaginatorAdapter($this->repo, $this->params, $this->apiKey);
|
||||
@@ -38,7 +38,7 @@ class NonOrphanVisitsPaginatorAdapterTest extends TestCase
|
||||
{
|
||||
$expectedCount = 5;
|
||||
$this->repo->expects($this->once())->method('countNonOrphanVisits')->with(
|
||||
new VisitsCountFiltering($this->params->dateRange, $this->params->excludeBots, $this->apiKey),
|
||||
new WithDomainVisitsCountFiltering($this->params->dateRange, $this->params->excludeBots, $this->apiKey),
|
||||
)->willReturn($expectedCount);
|
||||
|
||||
$result = $this->adapter->getNbResults();
|
||||
@@ -55,12 +55,12 @@ class NonOrphanVisitsPaginatorAdapterTest extends TestCase
|
||||
{
|
||||
$visitor = Visitor::empty();
|
||||
$list = [Visit::forRegularNotFound($visitor), Visit::forInvalidShortUrl($visitor)];
|
||||
$this->repo->expects($this->once())->method('findNonOrphanVisits')->with(new VisitsListFiltering(
|
||||
$this->repo->expects($this->once())->method('findNonOrphanVisits')->with(new WithDomainVisitsListFiltering(
|
||||
$this->params->dateRange,
|
||||
$this->params->excludeBots,
|
||||
$this->apiKey,
|
||||
$limit,
|
||||
$offset,
|
||||
limit: $limit,
|
||||
offset: $offset,
|
||||
))->willReturn($list);
|
||||
|
||||
$result = $this->adapter->getSlice($offset, $limit);
|
||||
|
||||
@@ -8,10 +8,10 @@ use PHPUnit\Framework\Attributes\Test;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Paginator\Adapter\TagVisitsPaginatorAdapter;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitRepositoryInterface;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
@@ -33,7 +33,7 @@ class VisitsForTagPaginatorAdapterTest extends TestCase
|
||||
$adapter = $this->createAdapter(null);
|
||||
$this->repo->expects($this->exactly($count))->method('findVisitsByTag')->with(
|
||||
'foo',
|
||||
new VisitsListFiltering(DateRange::allTime(), false, null, $limit, $offset),
|
||||
new WithDomainVisitsListFiltering(DateRange::allTime(), limit: $limit, offset: $offset),
|
||||
)->willReturn([]);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
@@ -49,7 +49,7 @@ class VisitsForTagPaginatorAdapterTest extends TestCase
|
||||
$adapter = $this->createAdapter($apiKey);
|
||||
$this->repo->expects($this->once())->method('countVisitsByTag')->with(
|
||||
'foo',
|
||||
new VisitsCountFiltering(DateRange::allTime(), false, $apiKey),
|
||||
new WithDomainVisitsCountFiltering(DateRange::allTime(), apiKey: $apiKey),
|
||||
)->willReturn(3);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
@@ -59,6 +59,6 @@ class VisitsForTagPaginatorAdapterTest extends TestCase
|
||||
|
||||
private function createAdapter(ApiKey|null $apiKey): TagVisitsPaginatorAdapter
|
||||
{
|
||||
return new TagVisitsPaginatorAdapter($this->repo, 'foo', VisitsParams::fromRawData([]), $apiKey);
|
||||
return new TagVisitsPaginatorAdapter($this->repo, 'foo', WithDomainVisitsParams::fromRawData([]), $apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ use Shlinkio\Shlink\Core\Visit\Model\OrphanVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\Visitor;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\OrphanVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsCountFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\WithDomainVisitsListFiltering;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\OrphanVisitsCountRepository;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\ShortUrlVisitsCountRepository;
|
||||
use Shlinkio\Shlink\Core\Visit\Repository\VisitRepository;
|
||||
@@ -147,7 +149,7 @@ class VisitsStatsHelperTest extends TestCase
|
||||
|
||||
$this->expectException(TagNotFoundException::class);
|
||||
|
||||
$this->helper->visitsForTag($tag, new VisitsParams(), $apiKey);
|
||||
$this->helper->visitsForTag($tag, new WithDomainVisitsParams(), $apiKey);
|
||||
}
|
||||
|
||||
#[Test, DataProviderExternal(ApiKeyDataProviders::class, 'adminApiKeysProvider')]
|
||||
@@ -170,7 +172,7 @@ class VisitsStatsHelperTest extends TestCase
|
||||
[Visit::class, $repo2],
|
||||
]);
|
||||
|
||||
$paginator = $this->helper->visitsForTag($tag, new VisitsParams(), $apiKey);
|
||||
$paginator = $this->helper->visitsForTag($tag, new WithDomainVisitsParams(), $apiKey);
|
||||
|
||||
self::assertEquals($list, ArrayUtils::iteratorToArray($paginator->getCurrentPageResults()));
|
||||
}
|
||||
@@ -265,14 +267,14 @@ class VisitsStatsHelperTest extends TestCase
|
||||
);
|
||||
$repo = $this->createMock(VisitRepository::class);
|
||||
$repo->expects($this->once())->method('countNonOrphanVisits')->with(
|
||||
$this->isInstanceOf(VisitsCountFiltering::class),
|
||||
$this->isInstanceOf(WithDOmainVisitsCountFiltering::class),
|
||||
)->willReturn(count($list));
|
||||
$repo->expects($this->once())->method('findNonOrphanVisits')->with(
|
||||
$this->isInstanceOf(VisitsListFiltering::class),
|
||||
$this->isInstanceOf(WithDOmainVisitsListFiltering::class),
|
||||
)->willReturn($list);
|
||||
$this->em->expects($this->once())->method('getRepository')->with(Visit::class)->willReturn($repo);
|
||||
|
||||
$paginator = $this->helper->nonOrphanVisits(new VisitsParams());
|
||||
$paginator = $this->helper->nonOrphanVisits(new WithDomainVisitsParams());
|
||||
|
||||
self::assertEquals($list, ArrayUtils::iteratorToArray($paginator->getCurrentPageResults()));
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtils;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\VisitsStatsHelperInterface;
|
||||
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
@@ -26,9 +25,8 @@ abstract class AbstractListVisitsAction extends AbstractRestAction
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$params = VisitsParams::fromRawData($request->getQueryParams());
|
||||
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
|
||||
$visits = $this->getVisitsPaginator($request, $params, $apiKey);
|
||||
$visits = $this->getVisitsPaginator($request, $apiKey);
|
||||
|
||||
return new JsonResponse(['visits' => PagerfantaUtils::serializePaginator($visits)]);
|
||||
}
|
||||
@@ -36,9 +34,5 @@ abstract class AbstractListVisitsAction extends AbstractRestAction
|
||||
/**
|
||||
* @return Pagerfanta<Visit>
|
||||
*/
|
||||
abstract protected function getVisitsPaginator(
|
||||
ServerRequestInterface $request,
|
||||
VisitsParams $params,
|
||||
ApiKey $apiKey,
|
||||
): Pagerfanta;
|
||||
abstract protected function getVisitsPaginator(ServerRequestInterface $request, ApiKey $apiKey): Pagerfanta;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,9 @@ class DomainVisitsAction extends AbstractListVisitsAction
|
||||
parent::__construct($visitsHelper);
|
||||
}
|
||||
|
||||
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
|
||||
protected function getVisitsPaginator(Request $request, ApiKey $apiKey): Pagerfanta
|
||||
{
|
||||
$params = VisitsParams::fromRawData($request->getQueryParams());
|
||||
$domain = $this->resolveDomainParam($request);
|
||||
return $this->visitsHelper->visitsForDomain($domain, $params, $apiKey);
|
||||
}
|
||||
|
||||
@@ -6,18 +6,16 @@ namespace Shlinkio\Shlink\Rest\Action\Visit;
|
||||
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class NonOrphanVisitsAction extends AbstractListVisitsAction
|
||||
{
|
||||
protected const string ROUTE_PATH = '/visits/non-orphan';
|
||||
|
||||
protected function getVisitsPaginator(
|
||||
ServerRequestInterface $request,
|
||||
VisitsParams $params,
|
||||
ApiKey $apiKey,
|
||||
): Pagerfanta {
|
||||
protected function getVisitsPaginator(ServerRequestInterface $request, ApiKey $apiKey): Pagerfanta
|
||||
{
|
||||
$params = WithDomainVisitsParams::fromRawData($request->getQueryParams());
|
||||
return $this->visitsHelper->nonOrphanVisits($params, $apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,19 +7,15 @@ namespace Shlinkio\Shlink\Rest\Action\Visit;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\OrphanVisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class OrphanVisitsAction extends AbstractListVisitsAction
|
||||
{
|
||||
protected const string ROUTE_PATH = '/visits/orphan';
|
||||
|
||||
protected function getVisitsPaginator(
|
||||
ServerRequestInterface $request,
|
||||
VisitsParams $params,
|
||||
ApiKey $apiKey,
|
||||
): Pagerfanta {
|
||||
$orphanParams = OrphanVisitsParams::fromVisitsParamsAndRawData($params, $request->getQueryParams());
|
||||
protected function getVisitsPaginator(ServerRequestInterface $request, ApiKey $apiKey): Pagerfanta
|
||||
{
|
||||
$orphanParams = OrphanVisitsParams::fromRawData($request->getQueryParams());
|
||||
return $this->visitsHelper->orphanVisits($orphanParams, $apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ class ShortUrlVisitsAction extends AbstractListVisitsAction
|
||||
{
|
||||
protected const string ROUTE_PATH = '/short-urls/{shortCode}/visits';
|
||||
|
||||
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
|
||||
protected function getVisitsPaginator(Request $request, ApiKey $apiKey): Pagerfanta
|
||||
{
|
||||
$params = VisitsParams::fromRawData($request->getQueryParams());
|
||||
$identifier = ShortUrlIdentifier::fromApiRequest($request);
|
||||
return $this->visitsHelper->visitsForShortUrl($identifier, $params, $apiKey);
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ namespace Shlinkio\Shlink\Rest\Action\Visit;
|
||||
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Visit\Model\WithDomainVisitsParams;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
class TagVisitsAction extends AbstractListVisitsAction
|
||||
{
|
||||
protected const string ROUTE_PATH = '/tags/{tag}/visits';
|
||||
|
||||
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
|
||||
protected function getVisitsPaginator(Request $request, ApiKey $apiKey): Pagerfanta
|
||||
{
|
||||
$params = WithDomainVisitsParams::fromRawData($request->getQueryParams());
|
||||
$tag = $request->getAttribute('tag', '');
|
||||
return $this->visitsHelper->visitsForTag($tag, $params, $apiKey);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user