Added helper service to avoid code duplication when resolving short URLs titles

This commit is contained in:
Alejandro Celaya
2021-02-05 17:59:34 +01:00
parent 71e91a541f
commit 608742c2e2
11 changed files with 159 additions and 81 deletions

View File

@@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\Core\Model;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Core\Exception\ValidationException;
use Shlinkio\Shlink\Core\ShortUrl\Helper\TitleResolutionModelInterface;
use Shlinkio\Shlink\Core\Validation\ShortUrlInputFilter;
use function array_key_exists;
@@ -13,7 +14,7 @@ use function Shlinkio\Shlink\Core\getOptionalBoolFromInputFilter;
use function Shlinkio\Shlink\Core\getOptionalIntFromInputFilter;
use function Shlinkio\Shlink\Core\parseDateField;
final class ShortUrlEdit
final class ShortUrlEdit implements TitleResolutionModelInterface
{
private bool $longUrlPropWasProvided = false;
private ?string $longUrl = null;
@@ -75,6 +76,11 @@ final class ShortUrlEdit
return $this->longUrl;
}
public function getLongUrl(): string
{
return $this->longUrl() ?? '';
}
public function longUrlWasProvided(): bool
{
return $this->longUrlPropWasProvided && $this->longUrl !== null;
@@ -133,6 +139,11 @@ final class ShortUrlEdit
return $this->titlePropWasProvided;
}
public function hasTitle(): bool
{
return $this->titleWasProvided();
}
public function titleWasAutoResolved(): bool
{
return $this->titleWasAutoResolved;

View File

@@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\Core\Model;
use Cake\Chronos\Chronos;
use Shlinkio\Shlink\Core\Exception\ValidationException;
use Shlinkio\Shlink\Core\ShortUrl\Helper\TitleResolutionModelInterface;
use Shlinkio\Shlink\Core\Validation\ShortUrlInputFilter;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
@@ -15,7 +16,7 @@ use function Shlinkio\Shlink\Core\parseDateField;
use const Shlinkio\Shlink\Core\DEFAULT_SHORT_CODES_LENGTH;
final class ShortUrlMeta
final class ShortUrlMeta implements TitleResolutionModelInterface
{
private string $longUrl;
private ?Chronos $validSince = null;

View File

@@ -15,26 +15,26 @@ use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelperInterface;
use Shlinkio\Shlink\Core\ShortUrl\Resolver\ShortUrlRelationResolverInterface;
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlService implements ShortUrlServiceInterface
{
private ORM\EntityManagerInterface $em;
private ShortUrlResolverInterface $urlResolver;
private UrlValidatorInterface $urlValidator;
private ShortUrlTitleResolutionHelperInterface $titleResolutionHelper;
private ShortUrlRelationResolverInterface $relationResolver;
public function __construct(
ORM\EntityManagerInterface $em,
ShortUrlResolverInterface $urlResolver,
UrlValidatorInterface $urlValidator,
ShortUrlTitleResolutionHelperInterface $titleResolutionHelper,
ShortUrlRelationResolverInterface $relationResolver
) {
$this->em = $em;
$this->urlResolver = $urlResolver;
$this->urlValidator = $urlValidator;
$this->titleResolutionHelper = $titleResolutionHelper;
$this->relationResolver = $relationResolver;
}
@@ -62,7 +62,8 @@ class ShortUrlService implements ShortUrlServiceInterface
?ApiKey $apiKey = null
): ShortUrl {
if ($shortUrlEdit->longUrlWasProvided()) {
$shortUrlEdit = $this->processTitleAndValidateUrl($shortUrlEdit);
/** @var ShortUrlEdit $shortUrlEdit */
$shortUrlEdit = $this->titleResolutionHelper->processTitleAndValidateUrl($shortUrlEdit);
}
$shortUrl = $this->urlResolver->resolveShortUrl($identifier, $apiKey);
@@ -72,15 +73,4 @@ class ShortUrlService implements ShortUrlServiceInterface
return $shortUrl;
}
private function processTitleAndValidateUrl(ShortUrlEdit $shortUrlEdit): ShortUrlEdit
{
if ($shortUrlEdit->titleWasProvided()) {
$this->urlValidator->validateUrl($shortUrlEdit->longUrl(), $shortUrlEdit->doValidateUrl());
return $shortUrlEdit;
}
$title = $this->urlValidator->validateUrlWithTitle($shortUrlEdit->longUrl(), $shortUrlEdit->doValidateUrl());
return $title === null ? $shortUrlEdit : $shortUrlEdit->withResolvedTitle($title);
}
}

View File

@@ -11,23 +11,23 @@ use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortCodeHelperInterface;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlTitleResolutionHelperInterface;
use Shlinkio\Shlink\Core\ShortUrl\Resolver\ShortUrlRelationResolverInterface;
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
class UrlShortener implements UrlShortenerInterface
{
private EntityManagerInterface $em;
private UrlValidatorInterface $urlValidator;
private ShortUrlTitleResolutionHelperInterface $titleResolutionHelper;
private ShortUrlRelationResolverInterface $relationResolver;
private ShortCodeHelperInterface $shortCodeHelper;
public function __construct(
UrlValidatorInterface $urlValidator,
ShortUrlTitleResolutionHelperInterface $titleResolutionHelper,
EntityManagerInterface $em,
ShortUrlRelationResolverInterface $relationResolver,
ShortCodeHelperInterface $shortCodeHelper
) {
$this->urlValidator = $urlValidator;
$this->titleResolutionHelper = $titleResolutionHelper;
$this->em = $em;
$this->relationResolver = $relationResolver;
$this->shortCodeHelper = $shortCodeHelper;
@@ -45,7 +45,8 @@ class UrlShortener implements UrlShortenerInterface
return $existingShortUrl;
}
$meta = $this->processTitleAndValidateUrl($meta);
/** @var ShortUrlMeta $meta */
$meta = $this->titleResolutionHelper->processTitleAndValidateUrl($meta);
return $this->em->transactional(function () use ($meta) {
$shortUrl = ShortUrl::fromMeta($meta, $this->relationResolver);
@@ -82,15 +83,4 @@ class UrlShortener implements UrlShortenerInterface
throw NonUniqueSlugException::fromSlug($shortUrlToBeCreated->getShortCode(), $domainAuthority);
}
}
private function processTitleAndValidateUrl(ShortUrlMeta $meta): ShortUrlMeta
{
if ($meta->hasTitle()) {
$this->urlValidator->validateUrl($meta->getLongUrl(), $meta->doValidateUrl());
return $meta;
}
$title = $this->urlValidator->validateUrlWithTitle($meta->getLongUrl(), $meta->doValidateUrl());
return $title === null ? $meta : $meta->withResolvedTitle($title);
}
}

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\ShortUrl\Helper;
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
class ShortUrlTitleResolutionHelper implements ShortUrlTitleResolutionHelperInterface
{
private UrlValidatorInterface $urlValidator;
public function __construct(UrlValidatorInterface $urlValidator)
{
$this->urlValidator = $urlValidator;
}
public function processTitleAndValidateUrl(TitleResolutionModelInterface $data): TitleResolutionModelInterface
{
if ($data->hasTitle()) {
$this->urlValidator->validateUrl($data->getLongUrl(), $data->doValidateUrl());
return $data;
}
$title = $this->urlValidator->validateUrlWithTitle($data->getLongUrl(), $data->doValidateUrl());
return $title === null ? $data : $data->withResolvedTitle($title);
}
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\ShortUrl\Helper;
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
interface ShortUrlTitleResolutionHelperInterface
{
/**
* @throws InvalidUrlException
*/
public function processTitleAndValidateUrl(TitleResolutionModelInterface $data): TitleResolutionModelInterface;
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\ShortUrl\Helper;
interface TitleResolutionModelInterface
{
public function hasTitle(): bool;
public function getLongUrl(): string;
public function doValidateUrl(): ?bool;
public function withResolvedTitle(string $title): self;
}