Ensured domain is taken into account when looking for a short URL

This commit is contained in:
Alejandro Celaya 2019-10-04 17:21:22 +02:00
parent 2ffaabe594
commit 49c3c9bec1
5 changed files with 19 additions and 9 deletions

View file

@ -117,14 +117,17 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
return $qb; return $qb;
} }
public function findOneByShortCode(string $shortCode): ?ShortUrl public function findOneByShortCode(string $shortCode, ?string $domain = null): ?ShortUrl
{ {
$dql= <<<DQL $dql= <<<DQL
SELECT s SELECT s
FROM Shlinkio\Shlink\Core\Entity\ShortUrl AS s FROM Shlinkio\Shlink\Core\Entity\ShortUrl AS s
LEFT JOIN s.domain AS d
WHERE s.shortCode = :shortCode WHERE s.shortCode = :shortCode
AND (s.validSince <= :now OR s.validSince IS NULL) AND (s.validSince <= :now OR s.validSince IS NULL)
AND (s.validUntil >= :now OR s.validUntil IS NULL) AND (s.validUntil >= :now OR s.validUntil IS NULL)
AND (s.domain IS NULL OR d.authority = :domain)
ORDER BY s.domain DESC
DQL; DQL;
$query = $this->getEntityManager()->createQuery($dql); $query = $this->getEntityManager()->createQuery($dql);
@ -132,11 +135,18 @@ DQL;
->setParameters([ ->setParameters([
'shortCode' => $shortCode, 'shortCode' => $shortCode,
'now' => Chronos::now(), 'now' => Chronos::now(),
'domain' => $domain,
]); ]);
/** @var ShortUrl|null $result */ // Since we ordered by domain DESC, we will have first the URL matching the domain, followed
$result = $query->getOneOrNullResult(); // by the one with no domain (if any), so it is safe to fetch 1 max result and we will get:
return $result === null || $result->maxVisitsReached() ? null : $result; // * 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 public function slugIsInUse(string $slug, ?string $domain = null): bool

View file

@ -26,7 +26,7 @@ interface ShortUrlRepositoryInterface extends ObjectRepository
*/ */
public function countList(?string $searchTerm = null, array $tags = []): int; 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; public function slugIsInUse(string $slug, ?string $domain): bool;
} }

View file

@ -175,7 +175,7 @@ class UrlShortener implements UrlShortenerInterface
* @throws InvalidShortCodeException * @throws InvalidShortCodeException
* @throws EntityDoesNotExistException * @throws EntityDoesNotExistException
*/ */
public function shortCodeToUrl(string $shortCode): ShortUrl public function shortCodeToUrl(string $shortCode, ?string $domain = null): ShortUrl
{ {
$chars = $this->options->getChars(); $chars = $this->options->getChars();
@ -186,7 +186,7 @@ class UrlShortener implements UrlShortenerInterface
/** @var ShortUrlRepository $shortUrlRepo */ /** @var ShortUrlRepository $shortUrlRepo */
$shortUrlRepo = $this->em->getRepository(ShortUrl::class); $shortUrlRepo = $this->em->getRepository(ShortUrl::class);
$shortUrl = $shortUrlRepo->findOneByShortCode($shortCode); $shortUrl = $shortUrlRepo->findOneByShortCode($shortCode, $domain);
if ($shortUrl === null) { if ($shortUrl === null) {
throw EntityDoesNotExistException::createFromEntityAndConditions(ShortUrl::class, [ throw EntityDoesNotExistException::createFromEntityAndConditions(ShortUrl::class, [
'shortCode' => $shortCode, 'shortCode' => $shortCode,

View file

@ -26,5 +26,5 @@ interface UrlShortenerInterface
* @throws InvalidShortCodeException * @throws InvalidShortCodeException
* @throws EntityDoesNotExistException * @throws EntityDoesNotExistException
*/ */
public function shortCodeToUrl(string $shortCode): ShortUrl; public function shortCodeToUrl(string $shortCode, ?string $domain = null): ShortUrl;
} }

View file

@ -247,7 +247,7 @@ class UrlShortenerTest extends TestCase
$shortUrl->setShortCode($shortCode); $shortUrl->setShortCode($shortCode);
$repo = $this->prophesize(ShortUrlRepositoryInterface::class); $repo = $this->prophesize(ShortUrlRepositoryInterface::class);
$repo->findOneByShortCode($shortCode)->willReturn($shortUrl); $repo->findOneByShortCode($shortCode, null)->willReturn($shortUrl);
$this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal()); $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
$url = $this->urlShortener->shortCodeToUrl($shortCode); $url = $this->urlShortener->shortCodeToUrl($shortCode);