refactor: move DQL in repositories

This commit is contained in:
Maël Gangloff
2025-10-21 12:52:43 +02:00
parent 1ae35231fe
commit 4facd7e951
12 changed files with 123 additions and 81 deletions

View File

@@ -34,22 +34,10 @@ class StatisticsController extends AbstractController
->setAlertSent($this->pool->getItem('stats.alert.sent')->get() ?? 0) ->setAlertSent($this->pool->getItem('stats.alert.sent')->get() ?? 0)
->setDomainTracked( ->setDomainTracked(
$this->getCachedItem('stats.domain.tracked', fn () => $this->watchListRepository->createQueryBuilder('w') $this->getCachedItem('stats.domain.tracked', fn () => $this->watchListRepository->getTrackedDomainCount())
->join('w.domains', 'd')
->select('COUNT(DISTINCT d.ldhName)')
->where('d.deleted = FALSE')
->getQuery()->getSingleColumnResult()[0])
) )
->setDomainCount( ->setDomainCount(
$this->getCachedItem('stats.domain.count', fn () => $this->domainRepository->createQueryBuilder('d') $this->getCachedItem('stats.domain.count', fn () => $this->domainRepository->getActiveDomainCountByTld())
->join('d.tld', 't')
->select('t.tld tld')
->addSelect('COUNT(d.ldhName) AS domain')
->addGroupBy('t.tld')
->where('d.deleted = FALSE')
->orderBy('domain', 'DESC')
->setMaxResults(5)
->getQuery()->getArrayResult())
) )
->setDomainCountTotal( ->setDomainCountTotal(
$this->getCachedItem('stats.domain.total', fn () => $this->domainRepository->count(['deleted' => false]) $this->getCachedItem('stats.domain.total', fn () => $this->domainRepository->count(['deleted' => false])

View File

@@ -110,16 +110,7 @@ class WatchListController extends AbstractController
/** @var Domain $domain */ /** @var Domain $domain */
foreach ($watchList->getDomains()->getIterator() as $domain) { foreach ($watchList->getDomains()->getIterator() as $domain) {
/** @var DomainEvent|null $exp */ /** @var DomainEvent|null $exp */
$exp = $this->domainEventRepository->createQueryBuilder('de') $exp = $this->domainEventRepository->findLastExpirationDomainEvent($domain);
->select()
->where('de.domain = :domain')
->andWhere('de.action = \'expiration\'')
->andWhere('de.deleted = FALSE')
->orderBy('de.date', 'DESC')
->setMaxResults(1)
->getQuery()
->setParameter('domain', $domain)
->getOneOrNullResult();
if (!$domain->getDeleted() && null !== $exp && !in_array($domain, $domains)) { if (!$domain->getDeleted() && null !== $exp && !in_array($domain, $domains)) {
$domains[] = $domain; $domains[] = $domain;

View File

@@ -64,15 +64,7 @@ final readonly class SendDomainEventNotifHandler
*/ */
/** @var DomainEvent[] $newEvents */ /** @var DomainEvent[] $newEvents */
$newEvents = $this->domainEventRepository->createQueryBuilder('de') $newEvents = $this->domainEventRepository->findNewDomainEvents($domain, $message->updatedAt);
->select()
->where('de.domain = :domain')
->andWhere('de.date > :updatedAt')
->andWhere('de.date < :now')
->setParameter('domain', $domain)
->setParameter('updatedAt', $message->updatedAt)
->setParameter('now', new \DateTimeImmutable())
->getQuery()->getResult();
foreach ($newEvents as $event) { foreach ($newEvents as $event) {
if (!in_array($event->getAction(), $watchList->getTrackedEvents())) { if (!in_array($event->getAction(), $watchList->getTrackedEvents())) {
@@ -111,15 +103,7 @@ final readonly class SendDomainEventNotifHandler
} }
/** @var DomainStatus $domainStatus */ /** @var DomainStatus $domainStatus */
$domainStatus = $this->domainStatusRepository->createQueryBuilder('ds') $domainStatus = $this->domainStatusRepository->findNewDomainStatus($domain, $message->updatedAt);
->select()
->where('ds.domain = :domain')
->andWhere('ds.date = :date')
->orderBy('ds.createdAt', 'DESC')
->setParameter('domain', $domain)
->setParameter('date', $message->updatedAt)
->getQuery()
->getOneOrNullResult();
if (null !== $domainStatus && count(array_intersect( if (null !== $domainStatus && count(array_intersect(
$watchList->getTrackedEppStatus(), $watchList->getTrackedEppStatus(),

View File

@@ -3,6 +3,7 @@
namespace App\MessageHandler; namespace App\MessageHandler;
use App\Message\UpdateRdapServers; use App\Message\UpdateRdapServers;
use App\Repository\DomainRepository;
use App\Service\OfficialDataService; use App\Service\OfficialDataService;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Attribute\AsMessageHandler;
@@ -17,7 +18,7 @@ final readonly class UpdateRdapServersHandler
{ {
public function __construct( public function __construct(
private OfficialDataService $officialDataService, private OfficialDataService $officialDataService,
private ParameterBagInterface $bag, private ParameterBagInterface $bag, private DomainRepository $domainRepository,
) { ) {
} }
@@ -41,7 +42,7 @@ final readonly class UpdateRdapServersHandler
try { try {
$this->officialDataService->updateTldListIANA(); $this->officialDataService->updateTldListIANA();
$this->officialDataService->updateGTldListICANN(); $this->officialDataService->updateGTldListICANN();
$this->officialDataService->updateDomainsWhenTldIsDeleted(); $this->domainRepository->setDomainDeletedIfTldIsDeleted();
} catch (\Throwable $throwable) { } catch (\Throwable $throwable) {
$throws[] = $throwable; $throws[] = $throwable;
} }

View File

@@ -2,6 +2,7 @@
namespace App\Repository; namespace App\Repository;
use App\Entity\Domain;
use App\Entity\DomainEntity; use App\Entity\DomainEntity;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
@@ -16,6 +17,18 @@ class DomainEntityRepository extends ServiceEntityRepository
parent::__construct($registry, DomainEntity::class); parent::__construct($registry, DomainEntity::class);
} }
public function setDomainEntityAsDeleted(Domain $domain)
{
return $this->createQueryBuilder('de')
->update()
->set('de.deletedAt', ':now')
->where('de.domain = :domain')
->andWhere('de.deletedAt IS NOT NULL')
->setParameter('now', new \DateTimeImmutable())
->setParameter('domain', $domain)
->getQuery()->execute();
}
// /** // /**
// * @return DomainEntity[] Returns an array of DomainEntity objects // * @return DomainEntity[] Returns an array of DomainEntity objects
// */ // */

View File

@@ -2,6 +2,7 @@
namespace App\Repository; namespace App\Repository;
use App\Entity\Domain;
use App\Entity\DomainEvent; use App\Entity\DomainEvent;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
@@ -16,6 +17,45 @@ class DomainEventRepository extends ServiceEntityRepository
parent::__construct($registry, DomainEvent::class); parent::__construct($registry, DomainEvent::class);
} }
public function findLastExpirationDomainEvent(Domain $domain)
{
return $this->createQueryBuilder('de')
->select()
->where('de.domain = :domain')
->andWhere('de.action = \'expiration\'')
->andWhere('de.deleted = FALSE')
->orderBy('de.date', 'DESC')
->setMaxResults(1)
->getQuery()
->setParameter('domain', $domain)
->getOneOrNullResult();
}
public function findNewDomainEvents(Domain $domain, \DateTimeImmutable $updatedAt)
{
return $this->createQueryBuilder('de')
->select()
->where('de.domain = :domain')
->andWhere('de.date > :updatedAt')
->andWhere('de.date < :now')
->setParameter('domain', $domain)
->setParameter('updatedAt', $updatedAt)
->setParameter('now', new \DateTimeImmutable())
->getQuery()->getResult();
}
public function setDomainEventAsDeleted(Domain $domain)
{
return $this->createQueryBuilder('de')
->update()
->set('de.deleted', ':deleted')
->where('de.domain = :domain')
->setParameter('deleted', true)
->setParameter('domain', $domain)
->getQuery()
->execute();
}
// /** // /**
// * @return DomainEvent[] Returns an array of DomainEvent objects // * @return DomainEvent[] Returns an array of DomainEvent objects
// */ // */

View File

@@ -3,6 +3,7 @@
namespace App\Repository; namespace App\Repository;
use App\Entity\Domain; use App\Entity\Domain;
use App\Entity\Tld;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
@@ -27,6 +28,29 @@ class DomainRepository extends ServiceEntityRepository
->getResult(); ->getResult();
} }
public function getActiveDomainCountByTld(): array
{
return $this->createQueryBuilder('d')
->select('t.tld tld')
->join('d.tld', 't')
->addSelect('COUNT(d.ldhName) AS domain')
->addGroupBy('t.tld')
->where('d.deleted = FALSE')
->orderBy('domain', 'DESC')
->setMaxResults(5)
->getQuery()->getArrayResult();
}
public function setDomainDeletedIfTldIsDeleted()
{
return $this->createQueryBuilder('d')
->update()
->set('d.deleted', ':deleted')
->where('d.tld IN (SELECT t FROM '.Tld::class.' t WHERE t.deletedAt IS NOT NULL)')
->setParameter('deleted', true)
->getQuery()->execute();
}
// /** // /**
// * @return Domain[] Returns an array of Domain objects // * @return Domain[] Returns an array of Domain objects
// */ // */

View File

@@ -2,6 +2,7 @@
namespace App\Repository; namespace App\Repository;
use App\Entity\Domain;
use App\Entity\DomainStatus; use App\Entity\DomainStatus;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
@@ -16,6 +17,19 @@ class DomainStatusRepository extends ServiceEntityRepository
parent::__construct($registry, DomainStatus::class); parent::__construct($registry, DomainStatus::class);
} }
public function findNewDomainStatus(Domain $domain, \DateTimeImmutable $updatedAt)
{
return $this->createQueryBuilder('ds')
->select()
->where('ds.domain = :domain')
->andWhere('ds.date = :date')
->orderBy('ds.createdAt', 'DESC')
->setParameter('domain', $domain)
->setParameter('date', $updatedAt)
->getQuery()
->getOneOrNullResult();
}
// /** // /**
// * @return DomainStatus[] Returns an array of DomainStatus objects // * @return DomainStatus[] Returns an array of DomainStatus objects
// */ // */

View File

@@ -28,6 +28,16 @@ class TldRepository extends ServiceEntityRepository
->getResult(); ->getResult();
} }
public function setAllTldAsDeleted()
{
return $this->createQueryBuilder('t')
->update()
->set('t.deletedAt', 'COALESCE(t.removalDate, CURRENT_TIMESTAMP())')
->where('t.tld != :dot')
->setParameter('dot', '.')
->getQuery()->execute();
}
// /** // /**
// * @return Tld[] Returns an array of Tld objects // * @return Tld[] Returns an array of Tld objects
// */ // */

View File

@@ -16,6 +16,15 @@ class WatchListRepository extends ServiceEntityRepository
parent::__construct($registry, WatchList::class); parent::__construct($registry, WatchList::class);
} }
public function getTrackedDomainCount()
{
return $this->createQueryBuilder('w')
->select('COUNT(DISTINCT d.ldhName)')
->join('w.domains', 'd')
->where('d.deleted = FALSE')
->getQuery()->getSingleScalarResult();
}
// /** // /**
// * @return WatchList[] Returns an array of WatchList objects // * @return WatchList[] Returns an array of WatchList objects
// */ // */

View File

@@ -7,7 +7,6 @@ use App\Config\TldType;
use App\Entity\IcannAccreditation; use App\Entity\IcannAccreditation;
use App\Entity\RdapServer; use App\Entity\RdapServer;
use App\Entity\Tld; use App\Entity\Tld;
use App\Repository\DomainRepository;
use App\Repository\IcannAccreditationRepository; use App\Repository\IcannAccreditationRepository;
use App\Repository\RdapServerRepository; use App\Repository\RdapServerRepository;
use App\Repository\TldRepository; use App\Repository\TldRepository;
@@ -63,8 +62,8 @@ class OfficialDataService
public const DOMAIN_DOT = '.'; public const DOMAIN_DOT = '.';
public function __construct(private HttpClientInterface $client, public function __construct(
private readonly DomainRepository $domainRepository, private readonly HttpClientInterface $client,
private readonly RdapServerRepository $rdapServerRepository, private readonly RdapServerRepository $rdapServerRepository,
private readonly TldRepository $tldRepository, private readonly TldRepository $tldRepository,
private readonly IcannAccreditationRepository $icannAccreditationRepository, private readonly IcannAccreditationRepository $icannAccreditationRepository,
@@ -165,12 +164,7 @@ class OfficialDataService
continue; continue;
} }
$this->tldRepository->createQueryBuilder('t') $this->tldRepository->setAllTldAsDeleted();
->update()
->set('t.deletedAt', 'COALESCE(t.removalDate, CURRENT_TIMESTAMP())')
->where('t.tld != :dot')
->setParameter('dot', self::DOMAIN_DOT)
->getQuery()->execute();
$tldEntity = $this->tldRepository->findOneBy(['tld' => $tld]); $tldEntity = $this->tldRepository->findOneBy(['tld' => $tld]);
@@ -305,14 +299,4 @@ class OfficialDataService
$this->em->flush(); $this->em->flush();
} }
public function updateDomainsWhenTldIsDeleted(): void
{
$this->domainRepository->createQueryBuilder('d')
->update()
->set('d.deleted', ':deleted')
->where('d.tld IN (SELECT t FROM '.Tld::class.' t WHERE t.deletedAt IS NOT NULL)')
->setParameter('deleted', true)
->getQuery()->execute();
}
} }

View File

@@ -355,14 +355,7 @@ class RDAPService
*/ */
private function updateDomainEvents(Domain $domain, array $rdapData): void private function updateDomainEvents(Domain $domain, array $rdapData): void
{ {
$this->domainEventRepository->createQueryBuilder('de') $this->domainEventRepository->setDomainEventAsDeleted($domain);
->update()
->set('de.deleted', ':deleted')
->where('de.domain = :domain')
->setParameter('deleted', true)
->setParameter('domain', $domain)
->getQuery()
->execute();
if (isset($rdapData['events']) && is_array($rdapData['events'])) { if (isset($rdapData['events']) && is_array($rdapData['events'])) {
foreach ($rdapData['events'] as $rdapEvent) { foreach ($rdapData['events'] as $rdapEvent) {
@@ -399,16 +392,7 @@ class RDAPService
*/ */
private function updateDomainEntities(Domain $domain, array $rdapData): void private function updateDomainEntities(Domain $domain, array $rdapData): void
{ {
$now = new \DateTimeImmutable(); $this->domainEntityRepository->setDomainEntityAsDeleted($domain);
$this->domainEntityRepository->createQueryBuilder('de')
->update()
->set('de.deletedAt', ':now')
->where('de.domain = :domain')
->andWhere('de.deletedAt IS NOT NULL')
->setParameter('now', $now)
->setParameter('domain', $domain)
->getQuery()->execute();
if (!isset($rdapData['entities']) || !is_array($rdapData['entities'])) { if (!isset($rdapData['entities']) || !is_array($rdapData['entities'])) {
return; return;