diff --git a/module/Core/src/Repository/ShortUrlRepository.php b/module/Core/src/Repository/ShortUrlRepository.php index b6fdb7f1..fb0a0625 100644 --- a/module/Core/src/Repository/ShortUrlRepository.php +++ b/module/Core/src/Repository/ShortUrlRepository.php @@ -117,14 +117,17 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI return $qb; } - public function findOneByShortCode(string $shortCode): ?ShortUrl + public function findOneByShortCode(string $shortCode, ?string $domain = null): ?ShortUrl { $dql= <<= :now OR s.validUntil IS NULL) + AND (s.domain IS NULL OR d.authority = :domain) + ORDER BY s.domain DESC DQL; $query = $this->getEntityManager()->createQuery($dql); @@ -132,11 +135,18 @@ DQL; ->setParameters([ 'shortCode' => $shortCode, 'now' => Chronos::now(), + 'domain' => $domain, ]); - /** @var ShortUrl|null $result */ - $result = $query->getOneOrNullResult(); - return $result === null || $result->maxVisitsReached() ? null : $result; + // Since we ordered by domain DESC, we will have first the URL matching the domain, followed + // by the one with no domain (if any), so it is safe to fetch 1 max result and we will get: + // * The short URL matching both the short code and the domain, or + // * The short URL matching the short code but without any domain, or + // * No short URL at all + + /** @var ShortUrl|null $shortUrl */ + $shortUrl = $query->getOneOrNullResult(); + return $shortUrl !== null && ! $shortUrl->maxVisitsReached() ? $shortUrl : null; } public function slugIsInUse(string $slug, ?string $domain = null): bool diff --git a/module/Core/src/Repository/ShortUrlRepositoryInterface.php b/module/Core/src/Repository/ShortUrlRepositoryInterface.php index b257f20a..22b6bd73 100644 --- a/module/Core/src/Repository/ShortUrlRepositoryInterface.php +++ b/module/Core/src/Repository/ShortUrlRepositoryInterface.php @@ -26,7 +26,7 @@ interface ShortUrlRepositoryInterface extends ObjectRepository */ public function countList(?string $searchTerm = null, array $tags = []): int; - public function findOneByShortCode(string $shortCode): ?ShortUrl; + public function findOneByShortCode(string $shortCode, ?string $domain = null): ?ShortUrl; public function slugIsInUse(string $slug, ?string $domain): bool; } diff --git a/module/Core/src/Service/UrlShortener.php b/module/Core/src/Service/UrlShortener.php index ec257e26..0d0c8b27 100644 --- a/module/Core/src/Service/UrlShortener.php +++ b/module/Core/src/Service/UrlShortener.php @@ -175,7 +175,7 @@ class UrlShortener implements UrlShortenerInterface * @throws InvalidShortCodeException * @throws EntityDoesNotExistException */ - public function shortCodeToUrl(string $shortCode): ShortUrl + public function shortCodeToUrl(string $shortCode, ?string $domain = null): ShortUrl { $chars = $this->options->getChars(); @@ -186,7 +186,7 @@ class UrlShortener implements UrlShortenerInterface /** @var ShortUrlRepository $shortUrlRepo */ $shortUrlRepo = $this->em->getRepository(ShortUrl::class); - $shortUrl = $shortUrlRepo->findOneByShortCode($shortCode); + $shortUrl = $shortUrlRepo->findOneByShortCode($shortCode, $domain); if ($shortUrl === null) { throw EntityDoesNotExistException::createFromEntityAndConditions(ShortUrl::class, [ 'shortCode' => $shortCode, diff --git a/module/Core/src/Service/UrlShortenerInterface.php b/module/Core/src/Service/UrlShortenerInterface.php index 314b6de2..4a200b4b 100644 --- a/module/Core/src/Service/UrlShortenerInterface.php +++ b/module/Core/src/Service/UrlShortenerInterface.php @@ -26,5 +26,5 @@ interface UrlShortenerInterface * @throws InvalidShortCodeException * @throws EntityDoesNotExistException */ - public function shortCodeToUrl(string $shortCode): ShortUrl; + public function shortCodeToUrl(string $shortCode, ?string $domain = null): ShortUrl; } diff --git a/module/Core/test/Service/UrlShortenerTest.php b/module/Core/test/Service/UrlShortenerTest.php index 891211af..77db0bae 100644 --- a/module/Core/test/Service/UrlShortenerTest.php +++ b/module/Core/test/Service/UrlShortenerTest.php @@ -247,7 +247,7 @@ class UrlShortenerTest extends TestCase $shortUrl->setShortCode($shortCode); $repo = $this->prophesize(ShortUrlRepositoryInterface::class); - $repo->findOneByShortCode($shortCode)->willReturn($shortUrl); + $repo->findOneByShortCode($shortCode, null)->willReturn($shortUrl); $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $url = $this->urlShortener->shortCodeToUrl($shortCode);