mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-10 17:23:12 +08:00
Add deviceLongUrls to short URL creation
This commit is contained in:
@@ -9,10 +9,20 @@ use Shlinkio\Shlink\Core\Model\DeviceType;
|
||||
|
||||
class DeviceLongUrl extends AbstractEntity
|
||||
{
|
||||
private function __construct(
|
||||
public function __construct(
|
||||
public readonly ShortUrl $shortUrl,
|
||||
public readonly DeviceType $deviceType,
|
||||
public readonly string $longUrl,
|
||||
private string $longUrl,
|
||||
) {
|
||||
}
|
||||
|
||||
public function longUrl(): string
|
||||
{
|
||||
return $this->longUrl;
|
||||
}
|
||||
|
||||
public function updateLongUrl(string $longUrl): void
|
||||
{
|
||||
$this->longUrl = $longUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ class ShortUrl extends AbstractEntity
|
||||
return self::create(ShortUrlCreation::createEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $longUrl
|
||||
*/
|
||||
public static function withLongUrl(string $longUrl): self
|
||||
{
|
||||
return self::create(ShortUrlCreation::fromRawData([ShortUrlInputFilter::LONG_URL => $longUrl]));
|
||||
@@ -75,19 +78,19 @@ class ShortUrl extends AbstractEntity
|
||||
$instance->longUrl = $creation->getLongUrl();
|
||||
$instance->dateCreated = Chronos::now();
|
||||
$instance->visits = new ArrayCollection();
|
||||
$instance->tags = $relationResolver->resolveTags($creation->getTags());
|
||||
$instance->validSince = $creation->getValidSince();
|
||||
$instance->validUntil = $creation->getValidUntil();
|
||||
$instance->maxVisits = $creation->getMaxVisits();
|
||||
$instance->tags = $relationResolver->resolveTags($creation->tags);
|
||||
$instance->validSince = $creation->validSince;
|
||||
$instance->validUntil = $creation->validUntil;
|
||||
$instance->maxVisits = $creation->maxVisits;
|
||||
$instance->customSlugWasProvided = $creation->hasCustomSlug();
|
||||
$instance->shortCodeLength = $creation->getShortCodeLength();
|
||||
$instance->shortCode = $creation->getCustomSlug() ?? generateRandomShortCode($instance->shortCodeLength);
|
||||
$instance->domain = $relationResolver->resolveDomain($creation->getDomain());
|
||||
$instance->authorApiKey = $creation->getApiKey();
|
||||
$instance->title = $creation->getTitle();
|
||||
$instance->titleWasAutoResolved = $creation->titleWasAutoResolved();
|
||||
$instance->crawlable = $creation->isCrawlable();
|
||||
$instance->forwardQuery = $creation->forwardQuery();
|
||||
$instance->shortCodeLength = $creation->shortCodeLength;
|
||||
$instance->shortCode = $creation->customSlug ?? generateRandomShortCode($instance->shortCodeLength);
|
||||
$instance->domain = $relationResolver->resolveDomain($creation->domain);
|
||||
$instance->authorApiKey = $creation->apiKey;
|
||||
$instance->title = $creation->title;
|
||||
$instance->titleWasAutoResolved = $creation->titleWasAutoResolved;
|
||||
$instance->crawlable = $creation->crawlable;
|
||||
$instance->forwardQuery = $creation->forwardQuery;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
@@ -6,85 +6,106 @@ namespace Shlinkio\Shlink\Core\ShortUrl\Model;
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
use Shlinkio\Shlink\Core\Exception\ValidationException;
|
||||
use Shlinkio\Shlink\Core\Model\DeviceType;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\TitleResolutionModelInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
use function Functional\map;
|
||||
use function Shlinkio\Shlink\Core\getNonEmptyOptionalValueFromInputFilter;
|
||||
use function Shlinkio\Shlink\Core\getOptionalBoolFromInputFilter;
|
||||
use function Shlinkio\Shlink\Core\getOptionalIntFromInputFilter;
|
||||
use function Shlinkio\Shlink\Core\normalizeOptionalDate;
|
||||
use function trim;
|
||||
|
||||
use const Shlinkio\Shlink\DEFAULT_SHORT_CODES_LENGTH;
|
||||
|
||||
final class ShortUrlCreation implements TitleResolutionModelInterface
|
||||
{
|
||||
private string $longUrl;
|
||||
private ?Chronos $validSince = null;
|
||||
private ?Chronos $validUntil = null;
|
||||
private ?string $customSlug = null;
|
||||
private ?int $maxVisits = null;
|
||||
private ?bool $findIfExists = null;
|
||||
private ?string $domain = null;
|
||||
private int $shortCodeLength = 5;
|
||||
private bool $validateUrl = false;
|
||||
private ?ApiKey $apiKey = null;
|
||||
private array $tags = [];
|
||||
private ?string $title = null;
|
||||
private bool $titleWasAutoResolved = false;
|
||||
private bool $crawlable = false;
|
||||
private bool $forwardQuery = true;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
/**
|
||||
* @param string[] $tags
|
||||
* @param array{DeviceType, string}[] $deviceLongUrls
|
||||
*/
|
||||
private function __construct(
|
||||
public readonly string $longUrl,
|
||||
public readonly array $deviceLongUrls = [],
|
||||
public readonly ?Chronos $validSince = null,
|
||||
public readonly ?Chronos $validUntil = null,
|
||||
public readonly ?string $customSlug = null,
|
||||
public readonly ?int $maxVisits = null,
|
||||
public readonly bool $findIfExists = false,
|
||||
public readonly ?string $domain = null,
|
||||
public readonly int $shortCodeLength = 5,
|
||||
public readonly bool $validateUrl = false,
|
||||
public readonly ?ApiKey $apiKey = null,
|
||||
public readonly array $tags = [],
|
||||
public readonly ?string $title = null,
|
||||
public readonly bool $titleWasAutoResolved = false,
|
||||
public readonly bool $crawlable = false,
|
||||
public readonly bool $forwardQuery = true,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function createEmpty(): self
|
||||
{
|
||||
$instance = new self();
|
||||
$instance->longUrl = '';
|
||||
|
||||
return $instance;
|
||||
return new self('');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public static function fromRawData(array $data): self
|
||||
{
|
||||
$instance = new self();
|
||||
$instance->validateAndInit($data);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ValidationException
|
||||
*/
|
||||
private function validateAndInit(array $data): void
|
||||
{
|
||||
$inputFilter = ShortUrlInputFilter::withRequiredLongUrl($data);
|
||||
if (! $inputFilter->isValid()) {
|
||||
throw ValidationException::fromInputFilter($inputFilter);
|
||||
}
|
||||
|
||||
$this->longUrl = $inputFilter->getValue(ShortUrlInputFilter::LONG_URL);
|
||||
$this->validSince = normalizeOptionalDate($inputFilter->getValue(ShortUrlInputFilter::VALID_SINCE));
|
||||
$this->validUntil = normalizeOptionalDate($inputFilter->getValue(ShortUrlInputFilter::VALID_UNTIL));
|
||||
$this->customSlug = $inputFilter->getValue(ShortUrlInputFilter::CUSTOM_SLUG);
|
||||
$this->maxVisits = getOptionalIntFromInputFilter($inputFilter, ShortUrlInputFilter::MAX_VISITS);
|
||||
$this->findIfExists = $inputFilter->getValue(ShortUrlInputFilter::FIND_IF_EXISTS);
|
||||
$this->validateUrl = getOptionalBoolFromInputFilter($inputFilter, ShortUrlInputFilter::VALIDATE_URL) ?? false;
|
||||
$this->domain = getNonEmptyOptionalValueFromInputFilter($inputFilter, ShortUrlInputFilter::DOMAIN);
|
||||
$this->shortCodeLength = getOptionalIntFromInputFilter(
|
||||
$inputFilter,
|
||||
ShortUrlInputFilter::SHORT_CODE_LENGTH,
|
||||
) ?? DEFAULT_SHORT_CODES_LENGTH;
|
||||
$this->apiKey = $inputFilter->getValue(ShortUrlInputFilter::API_KEY);
|
||||
$this->tags = $inputFilter->getValue(ShortUrlInputFilter::TAGS);
|
||||
$this->title = $inputFilter->getValue(ShortUrlInputFilter::TITLE);
|
||||
$this->crawlable = $inputFilter->getValue(ShortUrlInputFilter::CRAWLABLE);
|
||||
$this->forwardQuery = getOptionalBoolFromInputFilter($inputFilter, ShortUrlInputFilter::FORWARD_QUERY) ?? true;
|
||||
return new self(
|
||||
longUrl: $inputFilter->getValue(ShortUrlInputFilter::LONG_URL),
|
||||
deviceLongUrls: map(
|
||||
$inputFilter->getValue(ShortUrlInputFilter::DEVICE_LONG_URLS) ?? [],
|
||||
static fn (string $longUrl, string $deviceType) => [DeviceType::from($deviceType), trim($longUrl)],
|
||||
),
|
||||
validSince: normalizeOptionalDate($inputFilter->getValue(ShortUrlInputFilter::VALID_SINCE)),
|
||||
validUntil: normalizeOptionalDate($inputFilter->getValue(ShortUrlInputFilter::VALID_UNTIL)),
|
||||
customSlug: $inputFilter->getValue(ShortUrlInputFilter::CUSTOM_SLUG),
|
||||
maxVisits: getOptionalIntFromInputFilter($inputFilter, ShortUrlInputFilter::MAX_VISITS),
|
||||
findIfExists: $inputFilter->getValue(ShortUrlInputFilter::FIND_IF_EXISTS) ?? false,
|
||||
domain: getNonEmptyOptionalValueFromInputFilter($inputFilter, ShortUrlInputFilter::DOMAIN),
|
||||
shortCodeLength: getOptionalIntFromInputFilter(
|
||||
$inputFilter,
|
||||
ShortUrlInputFilter::SHORT_CODE_LENGTH,
|
||||
) ?? DEFAULT_SHORT_CODES_LENGTH,
|
||||
validateUrl: getOptionalBoolFromInputFilter($inputFilter, ShortUrlInputFilter::VALIDATE_URL) ?? false,
|
||||
apiKey: $inputFilter->getValue(ShortUrlInputFilter::API_KEY),
|
||||
tags: $inputFilter->getValue(ShortUrlInputFilter::TAGS),
|
||||
title: $inputFilter->getValue(ShortUrlInputFilter::TITLE),
|
||||
crawlable: $inputFilter->getValue(ShortUrlInputFilter::CRAWLABLE),
|
||||
forwardQuery: getOptionalBoolFromInputFilter($inputFilter, ShortUrlInputFilter::FORWARD_QUERY) ?? true,
|
||||
);
|
||||
}
|
||||
|
||||
public function withResolvedTitle(string $title): self
|
||||
{
|
||||
return new self(
|
||||
$this->longUrl,
|
||||
$this->deviceLongUrls,
|
||||
$this->validSince,
|
||||
$this->validUntil,
|
||||
$this->customSlug,
|
||||
$this->maxVisits,
|
||||
$this->findIfExists,
|
||||
$this->domain,
|
||||
$this->shortCodeLength,
|
||||
$this->validateUrl,
|
||||
$this->apiKey,
|
||||
$this->tags,
|
||||
$title,
|
||||
true,
|
||||
$this->crawlable,
|
||||
$this->forwardQuery,
|
||||
);
|
||||
}
|
||||
|
||||
public function getLongUrl(): string
|
||||
@@ -92,115 +113,38 @@ final class ShortUrlCreation implements TitleResolutionModelInterface
|
||||
return $this->longUrl;
|
||||
}
|
||||
|
||||
public function getValidSince(): ?Chronos
|
||||
{
|
||||
return $this->validSince;
|
||||
}
|
||||
|
||||
public function hasValidSince(): bool
|
||||
{
|
||||
return $this->validSince !== null;
|
||||
}
|
||||
|
||||
public function getValidUntil(): ?Chronos
|
||||
{
|
||||
return $this->validUntil;
|
||||
}
|
||||
|
||||
public function hasValidUntil(): bool
|
||||
{
|
||||
return $this->validUntil !== null;
|
||||
}
|
||||
|
||||
public function getCustomSlug(): ?string
|
||||
{
|
||||
return $this->customSlug;
|
||||
}
|
||||
|
||||
public function hasCustomSlug(): bool
|
||||
{
|
||||
return $this->customSlug !== null;
|
||||
}
|
||||
|
||||
public function getMaxVisits(): ?int
|
||||
{
|
||||
return $this->maxVisits;
|
||||
}
|
||||
|
||||
public function hasMaxVisits(): bool
|
||||
{
|
||||
return $this->maxVisits !== null;
|
||||
}
|
||||
|
||||
public function findIfExists(): bool
|
||||
{
|
||||
return (bool) $this->findIfExists;
|
||||
}
|
||||
|
||||
public function hasDomain(): bool
|
||||
{
|
||||
return $this->domain !== null;
|
||||
}
|
||||
|
||||
public function getDomain(): ?string
|
||||
{
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
public function getShortCodeLength(): int
|
||||
{
|
||||
return $this->shortCodeLength;
|
||||
}
|
||||
|
||||
public function doValidateUrl(): bool
|
||||
{
|
||||
return $this->validateUrl;
|
||||
}
|
||||
|
||||
public function getApiKey(): ?ApiKey
|
||||
{
|
||||
return $this->apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getTags(): array
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function getTitle(): ?string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function hasTitle(): bool
|
||||
{
|
||||
return $this->title !== null;
|
||||
}
|
||||
|
||||
public function titleWasAutoResolved(): bool
|
||||
{
|
||||
return $this->titleWasAutoResolved;
|
||||
}
|
||||
|
||||
public function withResolvedTitle(string $title): self
|
||||
{
|
||||
$copy = clone $this;
|
||||
$copy->title = $title;
|
||||
$copy->titleWasAutoResolved = true;
|
||||
|
||||
return $copy;
|
||||
}
|
||||
|
||||
public function isCrawlable(): bool
|
||||
{
|
||||
return $this->crawlable;
|
||||
}
|
||||
|
||||
public function forwardQuery(): bool
|
||||
{
|
||||
return $this->forwardQuery;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,20 @@ namespace Shlinkio\Shlink\Core\ShortUrl\Model\Validation;
|
||||
|
||||
use DateTime;
|
||||
use Laminas\Filter;
|
||||
use Laminas\InputFilter\Input;
|
||||
use Laminas\InputFilter\InputFilter;
|
||||
use Laminas\Validator;
|
||||
use Shlinkio\Shlink\Common\Validation;
|
||||
use Shlinkio\Shlink\Core\Config\EnvVars;
|
||||
use Shlinkio\Shlink\Core\Model\DeviceType;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
use function array_keys;
|
||||
use function array_values;
|
||||
use function Functional\contains;
|
||||
use function Functional\every;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function Shlinkio\Shlink\Core\enumValues;
|
||||
use function str_replace;
|
||||
use function substr;
|
||||
use function trim;
|
||||
@@ -32,6 +38,7 @@ class ShortUrlInputFilter extends InputFilter
|
||||
public const DOMAIN = 'domain';
|
||||
public const SHORT_CODE_LENGTH = 'shortCodeLength';
|
||||
public const LONG_URL = 'longUrl';
|
||||
public const DEVICE_LONG_URLS = 'deviceLongUrls';
|
||||
public const VALIDATE_URL = 'validateUrl';
|
||||
public const API_KEY = 'apiKey';
|
||||
public const TAGS = 'tags';
|
||||
@@ -57,16 +64,40 @@ class ShortUrlInputFilter extends InputFilter
|
||||
|
||||
private function initialize(bool $requireLongUrl, bool $multiSegmentEnabled): void
|
||||
{
|
||||
$longUrlInput = $this->createInput(self::LONG_URL, $requireLongUrl);
|
||||
$longUrlInput->getValidatorChain()->attach(new Validator\NotEmpty([
|
||||
$notEmptyValidator = new Validator\NotEmpty([
|
||||
Validator\NotEmpty::OBJECT,
|
||||
Validator\NotEmpty::SPACE,
|
||||
Validator\NotEmpty::NULL,
|
||||
Validator\NotEmpty::EMPTY_ARRAY,
|
||||
Validator\NotEmpty::BOOLEAN,
|
||||
]));
|
||||
Validator\NotEmpty::STRING,
|
||||
]);
|
||||
|
||||
$longUrlInput = $this->createInput(self::LONG_URL, $requireLongUrl);
|
||||
$longUrlInput->getValidatorChain()->attach($notEmptyValidator);
|
||||
$this->add($longUrlInput);
|
||||
|
||||
$deviceLongUrlsInput = $this->createInput(self::DEVICE_LONG_URLS, false);
|
||||
$deviceLongUrlsInput->getValidatorChain()->attach(
|
||||
new Validator\Callback(function (mixed $value) use ($notEmptyValidator): bool {
|
||||
if (! is_array($value)) {
|
||||
// TODO Set proper error: Not array
|
||||
return false;
|
||||
}
|
||||
|
||||
$validValues = enumValues(DeviceType::class);
|
||||
$keys = array_keys($value);
|
||||
if (! every($keys, static fn ($key) => contains($validValues, $key))) {
|
||||
// TODO Set proper error: Provided invalid device type
|
||||
return false;
|
||||
}
|
||||
|
||||
$longUrls = array_values($value);
|
||||
return every($longUrls, $notEmptyValidator->isValid(...));
|
||||
}),
|
||||
);
|
||||
$this->add($deviceLongUrlsInput);
|
||||
|
||||
$validSince = $this->createInput(self::VALID_SINCE, false);
|
||||
$validSince->getValidatorChain()->attach(new Validator\Date(['format' => DateTime::ATOM]));
|
||||
$this->add($validSince);
|
||||
@@ -75,8 +106,8 @@ class ShortUrlInputFilter extends InputFilter
|
||||
$validUntil->getValidatorChain()->attach(new Validator\Date(['format' => DateTime::ATOM]));
|
||||
$this->add($validUntil);
|
||||
|
||||
// FIXME The only way to enforce the NotEmpty validator to be evaluated when the value is provided but it's
|
||||
// empty, is by using the deprecated setContinueIfEmpty
|
||||
// The only way to enforce the NotEmpty validator to be evaluated when the key is present with an empty value
|
||||
// is by using the deprecated setContinueIfEmpty
|
||||
$customSlug = $this->createInput(self::CUSTOM_SLUG, false)->setContinueIfEmpty(true);
|
||||
$customSlug->getFilterChain()->attach(new Filter\Callback(match ($multiSegmentEnabled) {
|
||||
true => static fn (mixed $v) => is_string($v) ? trim(str_replace(' ', '-', $v), '/') : $v,
|
||||
@@ -102,10 +133,8 @@ class ShortUrlInputFilter extends InputFilter
|
||||
$domain->getValidatorChain()->attach(new Validation\HostAndPortValidator());
|
||||
$this->add($domain);
|
||||
|
||||
$apiKeyInput = new Input(self::API_KEY);
|
||||
$apiKeyInput
|
||||
->setRequired(false)
|
||||
->getValidatorChain()->attach(new Validator\IsInstanceOf(['className' => ApiKey::class]));
|
||||
$apiKeyInput = $this->createInput(self::API_KEY, false);
|
||||
$apiKeyInput->getValidatorChain()->attach(new Validator\IsInstanceOf(['className' => ApiKey::class]));
|
||||
$this->add($apiKeyInput);
|
||||
|
||||
$this->add($this->createTagsInput(self::TAGS, false));
|
||||
|
||||
@@ -101,45 +101,45 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function findOneMatching(ShortUrlCreation $meta): ?ShortUrl
|
||||
public function findOneMatching(ShortUrlCreation $creation): ?ShortUrl
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
|
||||
$qb->select('s')
|
||||
->from(ShortUrl::class, 's')
|
||||
->where($qb->expr()->eq('s.longUrl', ':longUrl'))
|
||||
->setParameter('longUrl', $meta->getLongUrl())
|
||||
->setParameter('longUrl', $creation->longUrl)
|
||||
->setMaxResults(1)
|
||||
->orderBy('s.id');
|
||||
|
||||
if ($meta->hasCustomSlug()) {
|
||||
if ($creation->hasCustomSlug()) {
|
||||
$qb->andWhere($qb->expr()->eq('s.shortCode', ':slug'))
|
||||
->setParameter('slug', $meta->getCustomSlug());
|
||||
->setParameter('slug', $creation->customSlug);
|
||||
}
|
||||
if ($meta->hasMaxVisits()) {
|
||||
if ($creation->hasMaxVisits()) {
|
||||
$qb->andWhere($qb->expr()->eq('s.maxVisits', ':maxVisits'))
|
||||
->setParameter('maxVisits', $meta->getMaxVisits());
|
||||
->setParameter('maxVisits', $creation->maxVisits);
|
||||
}
|
||||
if ($meta->hasValidSince()) {
|
||||
if ($creation->hasValidSince()) {
|
||||
$qb->andWhere($qb->expr()->eq('s.validSince', ':validSince'))
|
||||
->setParameter('validSince', $meta->getValidSince(), ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
->setParameter('validSince', $creation->validSince, ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
}
|
||||
if ($meta->hasValidUntil()) {
|
||||
if ($creation->hasValidUntil()) {
|
||||
$qb->andWhere($qb->expr()->eq('s.validUntil', ':validUntil'))
|
||||
->setParameter('validUntil', $meta->getValidUntil(), ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
->setParameter('validUntil', $creation->validUntil, ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
}
|
||||
if ($meta->hasDomain()) {
|
||||
if ($creation->hasDomain()) {
|
||||
$qb->join('s.domain', 'd')
|
||||
->andWhere($qb->expr()->eq('d.authority', ':domain'))
|
||||
->setParameter('domain', $meta->getDomain());
|
||||
->setParameter('domain', $creation->domain);
|
||||
}
|
||||
|
||||
$apiKey = $meta->getApiKey();
|
||||
$apiKey = $creation->apiKey;
|
||||
if ($apiKey !== null) {
|
||||
$this->applySpecification($qb, $apiKey->spec(), 's');
|
||||
}
|
||||
|
||||
$tags = $meta->getTags();
|
||||
$tags = $creation->tags;
|
||||
$tagsAmount = count($tags);
|
||||
if ($tagsAmount === 0) {
|
||||
return $qb->getQuery()->getOneOrNullResult();
|
||||
|
||||
@@ -22,7 +22,7 @@ interface ShortUrlRepositoryInterface extends ObjectRepository, EntitySpecificat
|
||||
|
||||
public function shortCodeIsInUseWithLock(ShortUrlIdentifier $identifier, ?Specification $spec = null): bool;
|
||||
|
||||
public function findOneMatching(ShortUrlCreation $meta): ?ShortUrl;
|
||||
public function findOneMatching(ShortUrlCreation $creation): ?ShortUrl;
|
||||
|
||||
public function findOneByImportedUrl(ImportedShlinkUrl $url): ?ShortUrl;
|
||||
}
|
||||
|
||||
@@ -57,15 +57,15 @@ class UrlShortener implements UrlShortenerInterface
|
||||
return $newShortUrl;
|
||||
}
|
||||
|
||||
private function findExistingShortUrlIfExists(ShortUrlCreation $meta): ?ShortUrl
|
||||
private function findExistingShortUrlIfExists(ShortUrlCreation $creation): ?ShortUrl
|
||||
{
|
||||
if (! $meta->findIfExists()) {
|
||||
if (! $creation->findIfExists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var ShortUrlRepositoryInterface $repo */
|
||||
$repo = $this->em->getRepository(ShortUrl::class);
|
||||
return $repo->findOneMatching($meta);
|
||||
return $repo->findOneMatching($creation);
|
||||
}
|
||||
|
||||
private function verifyShortCodeUniqueness(ShortUrlCreation $meta, ShortUrl $shortUrlToBeCreated): void
|
||||
|
||||
Reference in New Issue
Block a user