diff --git a/module/Core/src/Visit/Repository/VisitRepository.php b/module/Core/src/Visit/Repository/VisitRepository.php index e9123743..8b87954e 100644 --- a/module/Core/src/Visit/Repository/VisitRepository.php +++ b/module/Core/src/Visit/Repository/VisitRepository.php @@ -20,7 +20,6 @@ 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\Spec\CountOfNonOrphanVisits; use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\Entity\ApiKey; @@ -203,22 +202,40 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo */ public function findNonOrphanVisits(WithDomainVisitsListFiltering $filtering): array { + $qb = $this->createNonOrphanVisitsQueryBuilder($filtering); + return $this->resolveVisitsWithNativeQuery($qb, $filtering->limit, $filtering->offset); + } + + public function countNonOrphanVisits(WithDomainVisitsCountFiltering $filtering): int + { + $qb = $this->createNonOrphanVisitsQueryBuilder($filtering); + $qb->select('COUNT(v.id)'); + + return (int) $qb->getQuery()->getSingleScalarResult(); + } + + private function createNonOrphanVisitsQueryBuilder(WithDomainVisitsCountFiltering $filtering): QueryBuilder + { + $conn = $this->getEntityManager()->getConnection(); $qb = $this->createAllVisitsQueryBuilder($filtering); $qb->andWhere($qb->expr()->isNotNull('v.shortUrl')); $apiKey = $filtering->apiKey; - if (ApiKey::isShortUrlRestricted($apiKey)) { + $domain = $filtering->domain; + if (ApiKey::isShortUrlRestricted($apiKey) || $domain !== null) { $qb->join('v.shortUrl', 's'); } + if ($domain === Domain::DEFAULT_AUTHORITY) { + $qb->andWhere($qb->expr()->isNull('s.domain')); + } elseif ($domain !== null) { + $qb->join('s.domain', 'd') + ->andWhere($qb->expr()->eq('d.authority', $conn->quote($domain))); + } + $this->applySpecification($qb, $apiKey?->inlinedSpec(), 'v'); - return $this->resolveVisitsWithNativeQuery($qb, $filtering->limit, $filtering->offset); - } - - public function countNonOrphanVisits(VisitsCountFiltering $filtering): int - { - return (int) $this->matchSingleScalarResult(new CountOfNonOrphanVisits($filtering)); + return $qb; } private function createAllVisitsQueryBuilder(VisitsCountFiltering $filtering): QueryBuilder diff --git a/module/Core/src/Visit/Spec/CountOfNonOrphanVisits.php b/module/Core/src/Visit/Spec/CountOfNonOrphanVisits.php deleted file mode 100644 index d81cd21b..00000000 --- a/module/Core/src/Visit/Spec/CountOfNonOrphanVisits.php +++ /dev/null @@ -1,39 +0,0 @@ -filtering->dateRange), - ]; - - if ($this->filtering->excludeBots) { - $conditions[] = Spec::eq('potentialBot', false); - } - - $apiKey = $this->filtering->apiKey; - if ($apiKey !== null) { - $conditions[] = new WithApiKeySpecsEnsuringJoin($apiKey, 'shortUrl'); - } - - return Spec::countOf(Spec::andX(...$conditions)); - } -} diff --git a/module/Core/test-db/Visit/Repository/VisitRepositoryTest.php b/module/Core/test-db/Visit/Repository/VisitRepositoryTest.php index 6aa4f7b7..1b360005 100644 --- a/module/Core/test-db/Visit/Repository/VisitRepositoryTest.php +++ b/module/Core/test-db/Visit/Repository/VisitRepositoryTest.php @@ -339,13 +339,17 @@ class VisitRepositoryTest extends DatabaseTestCase $this->getEntityManager()->flush(); - self::assertEquals(4 + 5 + 7, $this->repo->countNonOrphanVisits(new VisitsCountFiltering())); + self::assertEquals(4 + 5 + 7, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering())); self::assertEquals(4 + 5 + 7, $this->countRepo->countNonOrphanVisits(new VisitsCountFiltering())); - self::assertEquals(4, $this->repo->countNonOrphanVisits(new VisitsCountFiltering(apiKey: $apiKey1))); + self::assertEquals(4, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering(apiKey: $apiKey1))); self::assertEquals(4, $this->countRepo->countNonOrphanVisits(new VisitsCountFiltering(apiKey: $apiKey1))); - self::assertEquals(5 + 7, $this->repo->countNonOrphanVisits(new VisitsCountFiltering(apiKey: $apiKey2))); + self::assertEquals(5 + 7, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering( + apiKey: $apiKey2, + ))); self::assertEquals(5 + 7, $this->countRepo->countNonOrphanVisits(new VisitsCountFiltering(apiKey: $apiKey2))); - self::assertEquals(4 + 7, $this->repo->countNonOrphanVisits(new VisitsCountFiltering(apiKey: $domainApiKey))); + self::assertEquals(4 + 7, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering( + apiKey: $domainApiKey, + ))); self::assertEquals(4 + 7, $this->countRepo->countNonOrphanVisits(new VisitsCountFiltering( apiKey: $domainApiKey, ))); @@ -355,21 +359,27 @@ class VisitRepositoryTest extends DatabaseTestCase self::assertEquals(0, $this->orphanCountRepo->countOrphanVisits(new OrphanVisitsCountFiltering( apiKey: $noOrphanVisitsApiKey, ))); - self::assertEquals(4, $this->repo->countNonOrphanVisits(new VisitsCountFiltering(DateRange::since( + self::assertEquals(4, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering(DateRange::since( Chronos::parse('2016-01-05')->startOfDay(), )))); - self::assertEquals(2, $this->repo->countNonOrphanVisits(new VisitsCountFiltering(DateRange::since( + self::assertEquals(2, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering(DateRange::since( Chronos::parse('2016-01-03')->startOfDay(), ), false, $apiKey1))); - self::assertEquals(1, $this->repo->countNonOrphanVisits(new VisitsCountFiltering(DateRange::since( + self::assertEquals(1, $this->repo->countNonOrphanVisits(new WithDomainVisitsCountFiltering(DateRange::since( Chronos::parse('2016-01-07')->startOfDay(), ), false, $apiKey2))); self::assertEquals(3 + 5, $this->repo->countNonOrphanVisits( - new VisitsCountFiltering(excludeBots: true, apiKey: $apiKey2), + new WithDomainVisitsCountFiltering(excludeBots: true, apiKey: $apiKey2), )); self::assertEquals(3 + 5, $this->countRepo->countNonOrphanVisits( new VisitsCountFiltering(excludeBots: true, apiKey: $apiKey2), )); + self::assertEquals(4 + 7, $this->repo->countNonOrphanVisits( + new WithDomainVisitsCountFiltering(domain: $domain->authority), + )); + self::assertEquals(5, $this->repo->countNonOrphanVisits( + new WithDomainVisitsCountFiltering(domain: Domain::DEFAULT_AUTHORITY), + )); self::assertEquals(4, $this->repo->countOrphanVisits(new OrphanVisitsCountFiltering())); self::assertEquals(4, $this->orphanCountRepo->countOrphanVisits(new OrphanVisitsCountFiltering())); self::assertEquals(3, $this->repo->countOrphanVisits(new OrphanVisitsCountFiltering(excludeBots: true)));