Added new models to pass to repositories when counting visits of any kind

This commit is contained in:
Alejandro Celaya
2021-05-22 20:16:32 +02:00
parent 9fa32b5b6b
commit 6327ed814a
14 changed files with 168 additions and 57 deletions

View File

@@ -16,12 +16,18 @@ final class VisitsParams
private ?DateRange $dateRange;
private int $page;
private int $itemsPerPage;
private bool $excludeBots;
public function __construct(?DateRange $dateRange = null, int $page = self::FIRST_PAGE, ?int $itemsPerPage = null)
{
public function __construct(
?DateRange $dateRange = null,
int $page = self::FIRST_PAGE,
?int $itemsPerPage = null,
bool $excludeBots = false
) {
$this->dateRange = $dateRange ?? new DateRange();
$this->page = $page;
$this->itemsPerPage = $this->determineItemsPerPage($itemsPerPage);
$this->excludeBots = $excludeBots;
}
private function determineItemsPerPage(?int $itemsPerPage): int
@@ -39,6 +45,7 @@ final class VisitsParams
parseDateRangeFromQuery($query, 'startDate', 'endDate'),
(int) ($query['page'] ?? 1),
isset($query['itemsPerPage']) ? (int) $query['itemsPerPage'] : null,
isset($query['excludeBots']),
);
}
@@ -56,4 +63,9 @@ final class VisitsParams
{
return $this->itemsPerPage;
}
public function excludeBots(): bool
{
return $this->excludeBots;
}
}

View File

@@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\Core\Paginator\Adapter;
use Shlinkio\Shlink\Core\Model\VisitsParams;
use Shlinkio\Shlink\Core\Repository\VisitRepositoryInterface;
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
{
@@ -20,7 +21,7 @@ class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
protected function doCount(): int
{
return $this->repo->countOrphanVisits($this->params->getDateRange());
return $this->repo->countOrphanVisits(new VisitsCountFiltering($this->params->getDateRange()));
}
public function getSlice($offset, $length): iterable // phpcs:ignore

View File

@@ -7,6 +7,7 @@ namespace Shlinkio\Shlink\Core\Paginator\Adapter;
use Happyr\DoctrineSpecification\Specification\Specification;
use Shlinkio\Shlink\Core\Model\VisitsParams;
use Shlinkio\Shlink\Core\Repository\VisitRepositoryInterface;
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class VisitsForTagPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
@@ -43,8 +44,11 @@ class VisitsForTagPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
{
return $this->visitRepository->countVisitsByTag(
$this->tag,
$this->params->getDateRange(),
$this->resolveSpec(),
new VisitsCountFiltering(
$this->params->getDateRange(),
$this->params->excludeBots(),
$this->resolveSpec(),
),
);
}

View File

@@ -8,6 +8,7 @@ use Happyr\DoctrineSpecification\Specification\Specification;
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
use Shlinkio\Shlink\Core\Model\VisitsParams;
use Shlinkio\Shlink\Core\Repository\VisitRepositoryInterface;
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
class VisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
{
@@ -45,8 +46,11 @@ class VisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
return $this->visitRepository->countVisitsByShortCode(
$this->identifier->shortCode(),
$this->identifier->domain(),
$this->params->getDateRange(),
$this->spec,
new VisitsCountFiltering(
$this->params->getDateRange(),
$this->params->excludeBots(),
$this->spec,
),
);
}
}

View File

@@ -12,6 +12,7 @@ use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Entity\VisitLocation;
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
use Shlinkio\Shlink\Core\Visit\Spec\CountOfOrphanVisits;
use Shlinkio\Shlink\Core\Visit\Spec\CountOfShortUrlVisits;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
@@ -95,13 +96,9 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
return $this->resolveVisitsWithNativeQuery($qb, $limit, $offset);
}
public function countVisitsByShortCode(
string $shortCode,
?string $domain = null,
?DateRange $dateRange = null,
?Specification $spec = null
): int {
$qb = $this->createVisitsByShortCodeQueryBuilder($shortCode, $domain, $dateRange, $spec);
public function countVisitsByShortCode(string $shortCode, ?string $domain, VisitsCountFiltering $filtering): int
{
$qb = $this->createVisitsByShortCodeQueryBuilder($shortCode, $domain, $filtering->dateRange(), $filtering->spec());
$qb->select('COUNT(v.id)');
return (int) $qb->getQuery()->getSingleScalarResult();
@@ -141,9 +138,9 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
return $this->resolveVisitsWithNativeQuery($qb, $limit, $offset);
}
public function countVisitsByTag(string $tag, ?DateRange $dateRange = null, ?Specification $spec = null): int
public function countVisitsByTag(string $tag, VisitsCountFiltering $filtering): int
{
$qb = $this->createVisitsByTagQueryBuilder($tag, $dateRange, $spec);
$qb = $this->createVisitsByTagQueryBuilder($tag, $filtering->dateRange(), $filtering->spec());
$qb->select('COUNT(v.id)');
return (int) $qb->getQuery()->getSingleScalarResult();
@@ -181,9 +178,9 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
return $this->resolveVisitsWithNativeQuery($qb, $limit, $offset);
}
public function countOrphanVisits(?DateRange $dateRange = null): int
public function countOrphanVisits(VisitsCountFiltering $filtering): int
{
return (int) $this->matchSingleScalarResult(new CountOfOrphanVisits($dateRange));
return (int) $this->matchSingleScalarResult(new CountOfOrphanVisits($filtering->dateRange()));
}
public function countVisits(?ApiKey $apiKey = null): int

View File

@@ -9,6 +9,7 @@ use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepositoryInterfa
use Happyr\DoctrineSpecification\Specification\Specification;
use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
interface VisitRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
@@ -42,12 +43,7 @@ interface VisitRepositoryInterface extends ObjectRepository, EntitySpecification
?Specification $spec = null
): array;
public function countVisitsByShortCode(
string $shortCode,
?string $domain = null,
?DateRange $dateRange = null,
?Specification $spec = null
): int;
public function countVisitsByShortCode(string $shortCode, ?string $domain, VisitsCountFiltering $filtering): int;
/**
* @return Visit[]
@@ -60,14 +56,14 @@ interface VisitRepositoryInterface extends ObjectRepository, EntitySpecification
?Specification $spec = null
): array;
public function countVisitsByTag(string $tag, ?DateRange $dateRange = null, ?Specification $spec = null): int;
public function countVisitsByTag(string $tag, VisitsCountFiltering $filtering): int;
/**
* @return Visit[]
*/
public function findOrphanVisits(?DateRange $dateRange = null, ?int $limit = null, ?int $offset = null): array;
public function countOrphanVisits(?DateRange $dateRange = null): int;
public function countOrphanVisits(VisitsCountFiltering $filtering): int;
public function countVisits(?ApiKey $apiKey = null): int;
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Visit\Persistence;
use Happyr\DoctrineSpecification\Specification\Specification;
use Shlinkio\Shlink\Common\Util\DateRange;
class VisitsCountFiltering
{
private ?DateRange $dateRange;
private bool $excludeBots;
private ?Specification $spec;
public function __construct(?DateRange $dateRange = null, bool $excludeBots = false, ?Specification $spec = null)
{
$this->dateRange = $dateRange;
$this->excludeBots = $excludeBots;
$this->spec = $spec;
}
public function dateRange(): ?DateRange
{
return $this->dateRange;
}
public function excludeBots(): bool
{
return $this->excludeBots;
}
public function spec(): ?Specification
{
return $this->spec;
}
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Visit\Persistence;
use Happyr\DoctrineSpecification\Specification\Specification;
use Shlinkio\Shlink\Common\Util\DateRange;
final class VisitsListFiltering extends VisitsCountFiltering
{
private ?int $limit;
private ?int $offset;
public function __construct(
?DateRange $dateRange = null,
bool $excludeBots = false,
?Specification $spec = null,
?int $limit = null,
?int $offset = null
) {
parent::__construct($dateRange, $excludeBots, $spec);
$this->limit = $limit;
$this->offset = $offset;
}
public function limit(): ?int
{
return $this->limit;
}
public function offset(): ?int
{
return $this->offset;
}
}

View File

@@ -22,6 +22,7 @@ use Shlinkio\Shlink\Core\Repository\TagRepository;
use Shlinkio\Shlink\Core\Repository\VisitRepository;
use Shlinkio\Shlink\Core\Repository\VisitRepositoryInterface;
use Shlinkio\Shlink\Core\Visit\Model\VisitsStats;
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class VisitsStatsHelper implements VisitsStatsHelperInterface
@@ -38,7 +39,10 @@ class VisitsStatsHelper implements VisitsStatsHelperInterface
/** @var VisitRepository $visitsRepo */
$visitsRepo = $this->em->getRepository(Visit::class);
return new VisitsStats($visitsRepo->countVisits($apiKey), $visitsRepo->countOrphanVisits());
return new VisitsStats(
$visitsRepo->countVisits($apiKey),
$visitsRepo->countOrphanVisits(new VisitsCountFiltering()),
);
}
/**