Merge pull request #1622 from acelaya-forks/feature/filter-out-disabled

Feature/filter out disabled
This commit is contained in:
Alejandro Celaya 2022-12-11 18:44:42 +01:00 committed by GitHub
commit 0b04476c99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 296 additions and 119 deletions

View file

@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
## [Unreleased]
### Added
* [#1612](https://github.com/shlinkio/shlink/issues/1612) Allowed to filter short URLs out of lists, when `validUntil` date is in the past or have reached their maximum amount of visits.
This can be done by:
* Providing `excludeMaxVisitsReached=true` and/or `excludePastValidUntil=true` to the `GET /short-urls` endpoint.
* Providing `--exclude-max-visits-reached` and/or `--exclude-past-valid-until` to the `short-urls:list` command.
* [#1616](https://github.com/shlinkio/shlink/issues/1616) Added support to import orphan visits when importing short URLs from another Shlink instance.
* [#1519](https://github.com/shlinkio/shlink/issues/1519) Allowing to search short URLs by default domain.
* [#1555](https://github.com/shlinkio/shlink/issues/1555) Added full support for PHP 8.2, pdating the dockr image to this version.

View file

@ -45,7 +45,7 @@
"php-middleware/request-id": "^4.1",
"pugx/shortid-php": "^1.1",
"ramsey/uuid": "^4.5",
"shlinkio/shlink-common": "dev-main#7515008 as 5.2",
"shlinkio/shlink-common": "dev-main#f4101bc as 5.2",
"shlinkio/shlink-config": "dev-main#96c81fb as 2.3",
"shlinkio/shlink-event-dispatcher": "^2.6",
"shlinkio/shlink-importer": "dev-main#c97662b as 5.0",

View file

@ -97,6 +97,32 @@
"schema": {
"type": "string"
}
},
{
"name": "excludeMaxVisitsReached",
"in": "query",
"description": "If true, short URLs which already reached their maximum amount of visits will be excluded.",
"required": false,
"schema": {
"type": "string",
"enum": [
"true",
"false"
]
}
},
{
"name": "excludePastValidUntil",
"in": "query",
"description": "If true, short URLs which validUntil date is on the past will be excluded.",
"required": false,
"schema": {
"type": "string",
"enum": [
"true",
"false"
]
}
}
],
"security": [

View file

@ -77,6 +77,18 @@ class ListShortUrlsCommand extends Command
InputOption::VALUE_NONE,
'If tags is provided, returns only short URLs having ALL tags.',
)
->addOption(
'exclude-max-visits-reached',
null,
InputOption::VALUE_NONE,
'Excludes short URLs which reached their max amount of visits.',
)
->addOption(
'exclude-past-valid-until',
null,
InputOption::VALUE_NONE,
'Excludes short URLs which have a "validUntil" date in the past.',
)
->addOption(
'order-by',
'o',
@ -133,6 +145,8 @@ class ListShortUrlsCommand extends Command
ShortUrlsParamsInputFilter::ORDER_BY => $orderBy,
ShortUrlsParamsInputFilter::START_DATE => $startDate?->toAtomString(),
ShortUrlsParamsInputFilter::END_DATE => $endDate?->toAtomString(),
ShortUrlsParamsInputFilter::EXCLUDE_MAX_VISITS_REACHED => $input->getOption('exclude-max-visits-reached'),
ShortUrlsParamsInputFilter::EXCLUDE_PAST_VALID_UNTIL => $input->getOption('exclude-past-valid-until'),
];
if ($all) {

View file

@ -61,6 +61,16 @@ class ListShortUrlsTest extends CliTestCase
| custom-with-domain | | http://some-domain.com/custom-with-domain | https://google.com | 2018-10-20T00:00:00+00:00 | 0 |
+--------------------+-------+-------------------------------------------+----------------------------- Page 1 of 1 -----------------------------------------------------------+---------------------------+--------------+
OUTPUT];
yield 'expired excluded' => [['--exclude-max-visits-reached', '--exclude-past-valid-until'], <<<OUTPUT
+--------------------+-------+-------------------------------------------+-----------------------------------------------------------------------------------------------------------+---------------------------+--------------+
| Short Code | Title | Short URL | Long URL | Date created | Visits count |
+--------------------+-------+-------------------------------------------+-----------------------------------------------------------------------------------------------------------+---------------------------+--------------+
| ghi789 | | http://example.com/ghi789 | https://blog.alejandrocelaya.com/2019/04/27/considerations-to-properly-use-open-source-software-projects/ | 2019-01-01T00:00:30+00:00 | 0 |
| custom | | http://doma.in/custom | https://shlink.io | 2019-01-01T00:00:20+00:00 | 0 |
| def456 | | http://doma.in/def456 | https://blog.alejandrocelaya.com/2017/12/09/acmailer-7-0-the-most-important-release-in-a-long-time/ | 2019-01-01T00:00:10+00:00 | 2 |
| custom-with-domain | | http://some-domain.com/custom-with-domain | https://google.com | 2018-10-20T00:00:00+00:00 | 0 |
+--------------------+-------+-------------------------------------------+-------------------------------- Page 1 of 1 --------------------------------------------------------------+---------------------------+--------------+
OUTPUT];
// phpcs:enable
}
}

View file

@ -114,7 +114,7 @@ class ListShortUrlsCommandTest extends TestCase
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with(
ShortUrlsParams::emptyInstance(),
)->willReturn(new Paginator(new ArrayAdapter([
ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo.com',
'tags' => ['foo', 'bar', 'baz'],
'apiKey' => $apiKey,

View file

@ -57,37 +57,37 @@ class ShortUrl extends AbstractEntity
public static function createEmpty(): self
{
return self::fromMeta(ShortUrlCreation::createEmpty());
return self::create(ShortUrlCreation::createEmpty());
}
public static function withLongUrl(string $longUrl): self
{
return self::fromMeta(ShortUrlCreation::fromRawData([ShortUrlInputFilter::LONG_URL => $longUrl]));
return self::create(ShortUrlCreation::fromRawData([ShortUrlInputFilter::LONG_URL => $longUrl]));
}
public static function fromMeta(
ShortUrlCreation $meta,
public static function create(
ShortUrlCreation $creation,
?ShortUrlRelationResolverInterface $relationResolver = null,
): self {
$instance = new self();
$relationResolver = $relationResolver ?? new SimpleShortUrlRelationResolver();
$instance->longUrl = $meta->getLongUrl();
$instance->longUrl = $creation->getLongUrl();
$instance->dateCreated = Chronos::now();
$instance->visits = new ArrayCollection();
$instance->tags = $relationResolver->resolveTags($meta->getTags());
$instance->validSince = $meta->getValidSince();
$instance->validUntil = $meta->getValidUntil();
$instance->maxVisits = $meta->getMaxVisits();
$instance->customSlugWasProvided = $meta->hasCustomSlug();
$instance->shortCodeLength = $meta->getShortCodeLength();
$instance->shortCode = $meta->getCustomSlug() ?? generateRandomShortCode($instance->shortCodeLength);
$instance->domain = $relationResolver->resolveDomain($meta->getDomain());
$instance->authorApiKey = $meta->getApiKey();
$instance->title = $meta->getTitle();
$instance->titleWasAutoResolved = $meta->titleWasAutoResolved();
$instance->crawlable = $meta->isCrawlable();
$instance->forwardQuery = $meta->forwardQuery();
$instance->tags = $relationResolver->resolveTags($creation->getTags());
$instance->validSince = $creation->getValidSince();
$instance->validUntil = $creation->getValidUntil();
$instance->maxVisits = $creation->getMaxVisits();
$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();
return $instance;
}
@ -109,7 +109,7 @@ class ShortUrl extends AbstractEntity
$meta[ShortUrlInputFilter::CUSTOM_SLUG] = $url->shortCode;
}
$instance = self::fromMeta(ShortUrlCreation::fromRawData($meta), $relationResolver);
$instance = self::create(ShortUrlCreation::fromRawData($meta), $relationResolver);
$instance->importSource = $url->source->value;
$instance->importOriginalShortCode = $url->shortCode;

View file

@ -24,6 +24,8 @@ final class ShortUrlsParams
public readonly array $tags,
public readonly Ordering $orderBy,
public readonly ?DateRange $dateRange,
public readonly bool $excludeMaxVisitsReached,
public readonly bool $excludePastValidUntil,
public readonly TagsMode $tagsMode = TagsMode::ANY,
) {
}
@ -55,6 +57,8 @@ final class ShortUrlsParams
normalizeOptionalDate($inputFilter->getValue(ShortUrlsParamsInputFilter::START_DATE)),
normalizeOptionalDate($inputFilter->getValue(ShortUrlsParamsInputFilter::END_DATE)),
),
excludeMaxVisitsReached: $inputFilter->getValue(ShortUrlsParamsInputFilter::EXCLUDE_MAX_VISITS_REACHED),
excludePastValidUntil: $inputFilter->getValue(ShortUrlsParamsInputFilter::EXCLUDE_PAST_VALID_UNTIL),
tagsMode: self::resolveTagsMode($inputFilter->getValue(ShortUrlsParamsInputFilter::TAGS_MODE)),
);
}

View file

@ -4,8 +4,15 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\ShortUrl\Model;
use function Functional\map;
enum TagsMode: string
{
case ANY = 'any';
case ALL = 'all';
public static function values(): array
{
return map(self::cases(), static fn (TagsMode $mode) => $mode->value);
}
}

View file

@ -23,6 +23,8 @@ class ShortUrlsParamsInputFilter extends InputFilter
public const ITEMS_PER_PAGE = 'itemsPerPage';
public const TAGS_MODE = 'tagsMode';
public const ORDER_BY = 'orderBy';
public const EXCLUDE_MAX_VISITS_REACHED = 'excludeMaxVisitsReached';
public const EXCLUDE_PAST_VALID_UNTIL = 'excludePastValidUntil';
public function __construct(array $data)
{
@ -44,11 +46,14 @@ class ShortUrlsParamsInputFilter extends InputFilter
$tagsMode = $this->createInput(self::TAGS_MODE, false);
$tagsMode->getValidatorChain()->attach(new InArray([
'haystack' => [TagsMode::ALL->value, TagsMode::ANY->value],
'haystack' => TagsMode::values(),
'strict' => InArray::COMPARE_STRICT,
]));
$this->add($tagsMode);
$this->add($this->createOrderByInput(self::ORDER_BY, ShortUrlsParams::ORDERABLE_FIELDS));
$this->add($this->createBooleanInput(self::EXCLUDE_MAX_VISITS_REACHED, false));
$this->add($this->createBooleanInput(self::EXCLUDE_PAST_VALID_UNTIL, false));
}
}

View file

@ -21,6 +21,8 @@ class ShortUrlsCountFiltering
public readonly array $tags = [],
public readonly ?TagsMode $tagsMode = null,
public readonly ?DateRange $dateRange = null,
public readonly bool $excludeMaxVisitsReached = false,
public readonly bool $excludePastValidUntil = false,
public readonly ?ApiKey $apiKey = null,
?string $defaultDomain = null,
) {
@ -37,6 +39,8 @@ class ShortUrlsCountFiltering
$params->tags,
$params->tagsMode,
$params->dateRange,
$params->excludeMaxVisitsReached,
$params->excludePastValidUntil,
$apiKey,
$defaultDomain,
);

View file

@ -20,10 +20,21 @@ class ShortUrlsListFiltering extends ShortUrlsCountFiltering
array $tags = [],
?TagsMode $tagsMode = null,
?DateRange $dateRange = null,
bool $excludeMaxVisitsReached = false,
bool $excludePastValidUntil = false,
?ApiKey $apiKey = null,
?string $defaultDomain = null,
) {
parent::__construct($searchTerm, $tags, $tagsMode, $dateRange, $apiKey, $defaultDomain);
parent::__construct(
$searchTerm,
$tags,
$tagsMode,
$dateRange,
$excludeMaxVisitsReached,
$excludePastValidUntil,
$apiKey,
$defaultDomain,
);
}
public static function fromLimitsAndParams(
@ -41,6 +52,8 @@ class ShortUrlsListFiltering extends ShortUrlsCountFiltering
$params->tags,
$params->tagsMode,
$params->dateRange,
$params->excludeMaxVisitsReached,
$params->excludePastValidUntil,
$apiKey,
$defaultDomain,
);

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\ShortUrl\Repository;
use Cake\Chronos\Chronos;
use Doctrine\DBAL\LockMode;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\ORM\Query\Expr\Join;
@ -11,18 +12,19 @@ use Doctrine\ORM\QueryBuilder;
use Happyr\DoctrineSpecification\Repository\EntitySpecificationRepository;
use Happyr\DoctrineSpecification\Specification\Specification;
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
use Shlinkio\Shlink\Core\Model\Ordering;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
use Shlinkio\Shlink\Core\ShortUrl\Model\TagsMode;
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsCountFiltering;
use Shlinkio\Shlink\Core\ShortUrl\Persistence\ShortUrlsListFiltering;
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
use function array_column;
use function count;
use function Functional\contains;
use function sprintf;
class ShortUrlRepository extends EntitySpecificationRepository implements ShortUrlRepositoryInterface
{
@ -37,36 +39,37 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
->setFirstResult($filtering->offset);
// In case the ordering has been specified, the query could be more complex. Process it
if ($filtering->orderBy->hasOrderField()) {
return $this->processOrderByForList($qb, $filtering->orderBy);
$this->processOrderByForList($qb, $filtering);
$result = $qb->getQuery()->getResult();
if ($filtering->orderBy->field === 'visits') {
return array_column($result, 0);
}
// With no explicit order by, fallback to dateCreated-DESC
return $qb->orderBy('s.dateCreated', 'DESC')->getQuery()->getResult();
return $result;
}
private function processOrderByForList(QueryBuilder $qb, Ordering $orderBy): array
private function processOrderByForList(QueryBuilder $qb, ShortUrlsListFiltering $filtering): void
{
$fieldName = $orderBy->field;
$order = $orderBy->direction;
// With no explicit order by, fallback to dateCreated-DESC
if (! $filtering->orderBy->hasOrderField()) {
$qb->orderBy('s.dateCreated', 'DESC');
return;
}
$fieldName = $filtering->orderBy->field;
$order = $filtering->orderBy->direction;
if ($fieldName === 'visits') {
// FIXME This query is inefficient.
// Diagnostic: It might need to use a sub-query, as done with the tags list query.
$qb->addSelect('COUNT(DISTINCT v) AS totalVisits')
$qb->addSelect('COUNT(DISTINCT v)')
->leftJoin('s.visits', 'v')
->groupBy('s')
->orderBy('totalVisits', $order);
return array_column($qb->getQuery()->getResult(), 0);
}
$orderableFields = ['longUrl', 'shortCode', 'dateCreated', 'title'];
if (contains($orderableFields, $fieldName)) {
->orderBy('COUNT(DISTINCT v)', $order);
} elseif (contains(['longUrl', 'shortCode', 'dateCreated', 'title'], $fieldName)) {
$qb->orderBy('s.' . $fieldName, $order);
}
return $qb->getQuery()->getResult();
}
public function countList(ShortUrlsCountFiltering $filtering): int
@ -134,6 +137,25 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
: $this->joinAllTags($qb, $tags);
}
if ($filtering->excludeMaxVisitsReached) {
$qb->andWhere($qb->expr()->orX(
$qb->expr()->isNull('s.maxVisits'),
$qb->expr()->gt(
's.maxVisits',
sprintf('(SELECT COUNT(innerV.id) FROM %s as innerV WHERE innerV.shortUrl=s)', Visit::class),
),
));
}
if ($filtering->excludePastValidUntil) {
$qb
->andWhere($qb->expr()->orX(
$qb->expr()->isNull('s.validUntil'),
$qb->expr()->gte('s.validUntil', ':minValidUntil'),
))
->setParameter('minValidUntil', Chronos::now()->toDateTimeString());
}
$this->applySpecification($qb, $filtering->apiKey?->spec(), 's');
return $qb;

View file

@ -44,7 +44,7 @@ class UrlShortener implements UrlShortenerInterface
/** @var ShortUrl $newShortUrl */
$newShortUrl = $this->em->wrapInTransaction(function () use ($meta) {
$shortUrl = ShortUrl::fromMeta($meta, $this->relationResolver);
$shortUrl = ShortUrl::create($meta, $this->relationResolver);
$this->verifyShortCodeUniqueness($meta, $shortUrl);
$this->em->persist($shortUrl);

View file

@ -129,7 +129,7 @@ class DomainRepositoryTest extends DatabaseTestCase
private function createShortUrl(Domain $domain, ?ApiKey $apiKey = null): ShortUrl
{
return ShortUrl::fromMeta(
return ShortUrl::create(
ShortUrlCreation::fromRawData(
['domain' => $domain->getAuthority(), 'apiKey' => $apiKey, 'longUrl' => 'foo'],
),

View file

@ -43,15 +43,15 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
/** @test */
public function findOneWithDomainFallbackReturnsProperData(): void
{
$regularOne = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['customSlug' => 'foo', 'longUrl' => 'foo']));
$regularOne = ShortUrl::create(ShortUrlCreation::fromRawData(['customSlug' => 'foo', 'longUrl' => 'foo']));
$this->getEntityManager()->persist($regularOne);
$withDomain = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
$withDomain = ShortUrl::create(ShortUrlCreation::fromRawData(
['domain' => 'example.com', 'customSlug' => 'domain-short-code', 'longUrl' => 'foo'],
));
$this->getEntityManager()->persist($withDomain);
$withDomainDuplicatingRegular = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
$withDomainDuplicatingRegular = ShortUrl::create(ShortUrlCreation::fromRawData(
['domain' => 'doma.in', 'customSlug' => 'foo', 'longUrl' => 'foo_with_domain'],
));
$this->getEntityManager()->persist($withDomainDuplicatingRegular);
@ -101,7 +101,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
/** @test */
public function findListProperlyFiltersResult(): void
{
$foo = ShortUrl::fromMeta(
$foo = ShortUrl::create(
ShortUrlCreation::fromRawData(['longUrl' => 'foo', 'tags' => ['bar']]),
$this->relationResolver,
);
@ -197,27 +197,27 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
/** @test */
public function findListReturnsOnlyThoseWithMatchingTags(): void
{
$shortUrl1 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo1',
'tags' => ['foo', 'bar'],
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl1);
$shortUrl2 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo2',
'tags' => ['foo', 'baz'],
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl2);
$shortUrl3 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl3 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo3',
'tags' => ['foo'],
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl3);
$shortUrl4 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl4 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo4',
'tags' => ['bar', 'baz'],
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl4);
$shortUrl5 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl5 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo5',
'tags' => ['bar', 'baz'],
]), $this->relationResolver);
@ -306,17 +306,17 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
/** @test */
public function findListReturnsOnlyThoseWithMatchingDomains(): void
{
$shortUrl1 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo1',
'domain' => null,
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl1);
$shortUrl2 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo2',
'domain' => null,
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl2);
$shortUrl3 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl3 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo3',
'domain' => 'another.com',
]), $this->relationResolver);
@ -339,15 +339,63 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
self::assertCount(0, $this->repo->findList($buildFiltering('no results')));
}
/** @test */
public function findListReturnsOnlyThoseWithoutExcludedUrls(): void
{
$shortUrl1 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo1',
'validUntil' => Chronos::now()->addDays(1)->toAtomString(),
'maxVisits' => 100,
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl1);
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo2',
'validUntil' => Chronos::now()->subDays(1)->toAtomString(),
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl2);
$shortUrl3 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo3',
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl3);
$shortUrl4 = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo4',
'maxVisits' => 3,
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl4);
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl4, Visitor::emptyInstance()));
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl4, Visitor::emptyInstance()));
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl4, Visitor::emptyInstance()));
$this->getEntityManager()->flush();
$filtering = static fn (bool $excludeMaxVisitsReached, bool $excludePastValidUntil) =>
new ShortUrlsListFiltering(
null,
null,
Ordering::emptyInstance(),
excludeMaxVisitsReached: $excludeMaxVisitsReached,
excludePastValidUntil: $excludePastValidUntil,
);
self::assertCount(4, $this->repo->findList($filtering(false, false)));
self::assertEquals(4, $this->repo->countList($filtering(false, false)));
self::assertCount(3, $this->repo->findList($filtering(true, false)));
self::assertEquals(3, $this->repo->countList($filtering(true, false)));
self::assertCount(3, $this->repo->findList($filtering(false, true)));
self::assertEquals(3, $this->repo->countList($filtering(false, true)));
self::assertCount(2, $this->repo->findList($filtering(true, true)));
self::assertEquals(2, $this->repo->countList($filtering(true, true)));
}
/** @test */
public function shortCodeIsInUseLooksForShortUrlInProperSetOfTables(): void
{
$shortUrlWithoutDomain = ShortUrl::fromMeta(
$shortUrlWithoutDomain = ShortUrl::create(
ShortUrlCreation::fromRawData(['customSlug' => 'my-cool-slug', 'longUrl' => 'foo']),
);
$this->getEntityManager()->persist($shortUrlWithoutDomain);
$shortUrlWithDomain = ShortUrl::fromMeta(
$shortUrlWithDomain = ShortUrl::create(
ShortUrlCreation::fromRawData(['domain' => 'doma.in', 'customSlug' => 'another-slug', 'longUrl' => 'foo']),
);
$this->getEntityManager()->persist($shortUrlWithDomain);
@ -371,12 +419,12 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
/** @test */
public function findOneLooksForShortUrlInProperSetOfTables(): void
{
$shortUrlWithoutDomain = ShortUrl::fromMeta(
$shortUrlWithoutDomain = ShortUrl::create(
ShortUrlCreation::fromRawData(['customSlug' => 'my-cool-slug', 'longUrl' => 'foo']),
);
$this->getEntityManager()->persist($shortUrlWithoutDomain);
$shortUrlWithDomain = ShortUrl::fromMeta(
$shortUrlWithDomain = ShortUrl::create(
ShortUrlCreation::fromRawData(['domain' => 'doma.in', 'customSlug' => 'another-slug', 'longUrl' => 'foo']),
);
$this->getEntityManager()->persist($shortUrlWithDomain);
@ -417,29 +465,29 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
$start = Chronos::parse('2020-03-05 20:18:30');
$end = Chronos::parse('2021-03-05 20:18:30');
$shortUrl = ShortUrl::fromMeta(
$shortUrl = ShortUrl::create(
ShortUrlCreation::fromRawData(['validSince' => $start, 'longUrl' => 'foo', 'tags' => ['foo', 'bar']]),
$this->relationResolver,
);
$this->getEntityManager()->persist($shortUrl);
$shortUrl2 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['validUntil' => $end, 'longUrl' => 'bar']));
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData(['validUntil' => $end, 'longUrl' => 'bar']));
$this->getEntityManager()->persist($shortUrl2);
$shortUrl3 = ShortUrl::fromMeta(
$shortUrl3 = ShortUrl::create(
ShortUrlCreation::fromRawData(['validSince' => $start, 'validUntil' => $end, 'longUrl' => 'baz']),
);
$this->getEntityManager()->persist($shortUrl3);
$shortUrl4 = ShortUrl::fromMeta(
$shortUrl4 = ShortUrl::create(
ShortUrlCreation::fromRawData(['customSlug' => 'custom', 'validUntil' => $end, 'longUrl' => 'foo']),
);
$this->getEntityManager()->persist($shortUrl4);
$shortUrl5 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => 'foo']));
$shortUrl5 = ShortUrl::create(ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => 'foo']));
$this->getEntityManager()->persist($shortUrl5);
$shortUrl6 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['domain' => 'doma.in', 'longUrl' => 'foo']));
$shortUrl6 = ShortUrl::create(ShortUrlCreation::fromRawData(['domain' => 'doma.in', 'longUrl' => 'foo']));
$this->getEntityManager()->persist($shortUrl6);
$this->getEntityManager()->flush();
@ -489,15 +537,15 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
['validSince' => $start, 'maxVisits' => 50, 'longUrl' => 'foo', 'tags' => $tags],
);
$shortUrl1 = ShortUrl::fromMeta($meta, $this->relationResolver);
$shortUrl1 = ShortUrl::create($meta, $this->relationResolver);
$this->getEntityManager()->persist($shortUrl1);
$this->getEntityManager()->flush();
$shortUrl2 = ShortUrl::fromMeta($meta, $this->relationResolver);
$shortUrl2 = ShortUrl::create($meta, $this->relationResolver);
$this->getEntityManager()->persist($shortUrl2);
$this->getEntityManager()->flush();
$shortUrl3 = ShortUrl::fromMeta($meta, $this->relationResolver);
$shortUrl3 = ShortUrl::create($meta, $this->relationResolver);
$this->getEntityManager()->persist($shortUrl3);
$this->getEntityManager()->flush();
@ -531,7 +579,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
$adminApiKey = ApiKey::create();
$this->getEntityManager()->persist($adminApiKey);
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
'validSince' => $start,
'apiKey' => $apiKey,
'domain' => $rightDomain->getAuthority(),
@ -540,7 +588,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
]), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl);
$nonDomainShortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$nonDomainShortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
'apiKey' => $apiKey,
'longUrl' => 'non-domain',
]), $this->relationResolver);
@ -659,7 +707,7 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
/** @test */
public function findCrawlableShortCodesReturnsExpectedResult(): void
{
$createShortUrl = fn (bool $crawlable) => ShortUrl::fromMeta(
$createShortUrl = fn (bool $crawlable) => ShortUrl::create(
ShortUrlCreation::fromRawData(['crawlable' => $crawlable, 'longUrl' => 'foo.com']),
);

View file

@ -77,22 +77,22 @@ class TagRepositoryTest extends DatabaseTestCase
['longUrl' => '', 'tags' => $tags, 'apiKey' => $apiKey],
);
$shortUrl = ShortUrl::fromMeta($metaWithTags($firstUrlTags, $apiKey), $this->relationResolver);
$shortUrl = ShortUrl::create($metaWithTags($firstUrlTags, $apiKey), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl);
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()));
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()));
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()));
$shortUrl2 = ShortUrl::fromMeta($metaWithTags($secondUrlTags, null), $this->relationResolver);
$shortUrl2 = ShortUrl::create($metaWithTags($secondUrlTags, null), $this->relationResolver);
$this->getEntityManager()->persist($shortUrl2);
$this->getEntityManager()->persist(Visit::forValidShortUrl($shortUrl2, Visitor::emptyInstance()));
// One of the tags has two extra short URLs, but with no visits
$this->getEntityManager()->persist(
ShortUrl::fromMeta($metaWithTags(['bar'], null), $this->relationResolver),
ShortUrl::create($metaWithTags(['bar'], null), $this->relationResolver),
);
$this->getEntityManager()->persist(
ShortUrl::fromMeta($metaWithTags(['bar'], $apiKey), $this->relationResolver),
ShortUrl::create($metaWithTags(['bar'], $apiKey), $this->relationResolver),
);
$this->getEntityManager()->flush();
@ -222,13 +222,13 @@ class TagRepositoryTest extends DatabaseTestCase
[$firstUrlTags, $secondUrlTags] = array_chunk($names, 3);
$shortUrl = ShortUrl::fromMeta(
$shortUrl = ShortUrl::create(
ShortUrlCreation::fromRawData(['apiKey' => $authorApiKey, 'longUrl' => '', 'tags' => $firstUrlTags]),
$this->relationResolver,
);
$this->getEntityManager()->persist($shortUrl);
$shortUrl2 = ShortUrl::fromMeta(
$shortUrl2 = ShortUrl::create(
ShortUrlCreation::fromRawData(
['domain' => $domain->getAuthority(), 'longUrl' => '', 'tags' => $secondUrlTags],
),

View file

@ -313,7 +313,7 @@ class VisitRepositoryTest extends DatabaseTestCase
$apiKey1 = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forAuthoredShortUrls()));
$this->getEntityManager()->persist($apiKey1);
$shortUrl = ShortUrl::fromMeta(
$shortUrl = ShortUrl::create(
ShortUrlCreation::fromRawData(['apiKey' => $apiKey1, 'domain' => $domain->getAuthority(), 'longUrl' => '']),
$this->relationResolver,
);
@ -322,11 +322,11 @@ class VisitRepositoryTest extends DatabaseTestCase
$apiKey2 = ApiKey::fromMeta(ApiKeyMeta::withRoles(RoleDefinition::forAuthoredShortUrls()));
$this->getEntityManager()->persist($apiKey2);
$shortUrl2 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['apiKey' => $apiKey2, 'longUrl' => '']));
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData(['apiKey' => $apiKey2, 'longUrl' => '']));
$this->getEntityManager()->persist($shortUrl2);
$this->createVisitsForShortUrl($shortUrl2, 5);
$shortUrl3 = ShortUrl::fromMeta(
$shortUrl3 = ShortUrl::create(
ShortUrlCreation::fromRawData(['apiKey' => $apiKey2, 'domain' => $domain->getAuthority(), 'longUrl' => '']),
$this->relationResolver,
);
@ -365,7 +365,7 @@ class VisitRepositoryTest extends DatabaseTestCase
/** @test */
public function findOrphanVisitsReturnsExpectedResult(): void
{
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['longUrl' => '']));
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '']));
$this->getEntityManager()->persist($shortUrl);
$this->createVisitsForShortUrl($shortUrl, 7);
@ -414,7 +414,7 @@ class VisitRepositoryTest extends DatabaseTestCase
/** @test */
public function countOrphanVisitsReturnsExpectedResult(): void
{
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['longUrl' => '']));
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '']));
$this->getEntityManager()->persist($shortUrl);
$this->createVisitsForShortUrl($shortUrl, 7);
@ -451,15 +451,15 @@ class VisitRepositoryTest extends DatabaseTestCase
/** @test */
public function findNonOrphanVisitsReturnsExpectedResult(): void
{
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['longUrl' => '1']));
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '1']));
$this->getEntityManager()->persist($shortUrl);
$this->createVisitsForShortUrl($shortUrl, 7);
$shortUrl2 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['longUrl' => '2']));
$shortUrl2 = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '2']));
$this->getEntityManager()->persist($shortUrl2);
$this->createVisitsForShortUrl($shortUrl2, 4);
$shortUrl3 = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['longUrl' => '3']));
$shortUrl3 = ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => '3']));
$this->getEntityManager()->persist($shortUrl3);
$this->createVisitsForShortUrl($shortUrl3, 10);
@ -517,7 +517,7 @@ class VisitRepositoryTest extends DatabaseTestCase
array $tags = [],
?ApiKey $apiKey = null,
): array {
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
ShortUrlInputFilter::LONG_URL => '',
ShortUrlInputFilter::TAGS => $tags,
ShortUrlInputFilter::API_KEY => $apiKey,
@ -529,7 +529,7 @@ class VisitRepositoryTest extends DatabaseTestCase
$this->createVisitsForShortUrl($shortUrl);
if ($withDomain !== false) {
$shortUrlWithDomain = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrlWithDomain = ShortUrl::create(ShortUrlCreation::fromRawData([
'customSlug' => $shortCode,
'domain' => $domain,
'longUrl' => '',

View file

@ -35,7 +35,7 @@ class PublishingUpdatesGeneratorTest extends TestCase
*/
public function visitIsProperlySerializedIntoUpdate(string $method, string $expectedTopic, ?string $title): void
{
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
'customSlug' => 'foo',
'longUrl' => '',
'title' => $title,
@ -114,7 +114,7 @@ class PublishingUpdatesGeneratorTest extends TestCase
/** @test */
public function shortUrlIsProperlySerializedIntoUpdate(): void
{
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
'customSlug' => 'foo',
'longUrl' => '',
'title' => 'The title',

View file

@ -98,7 +98,7 @@ class NotifyVisitToRabbitMqTest extends TestCase
yield 'orphan visit' => [Visit::forBasePath($visitor), ['newOrphanVisitUpdate']];
yield 'non-orphan visit' => [
Visit::forValidShortUrl(
ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'foo',
'customSlug' => 'bar',
])),

View file

@ -38,7 +38,7 @@ class ShortUrlTest extends TestCase
public function provideInvalidShortUrls(): iterable
{
yield 'with custom slug' => [
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['customSlug' => 'custom-slug', 'longUrl' => ''])),
ShortUrl::create(ShortUrlCreation::fromRawData(['customSlug' => 'custom-slug', 'longUrl' => ''])),
'The short code cannot be regenerated on ShortUrls where a custom slug was provided.',
];
yield 'already persisted' => [
@ -77,7 +77,7 @@ class ShortUrlTest extends TestCase
*/
public function shortCodesHaveExpectedLength(?int $length, int $expectedLength): void
{
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(
[ShortUrlInputFilter::SHORT_CODE_LENGTH => $length, 'longUrl' => ''],
));

View file

@ -30,7 +30,7 @@ class ShortUrlRedirectionBuilderTest extends TestCase
?string $extraPath,
?bool $forwardQuery,
): void {
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'https://domain.com/foo/bar?some=thing',
'forwardQuery' => $forwardQuery,
]));

View file

@ -28,7 +28,7 @@ class ShortUrlStringifierTest extends TestCase
public function provideConfigAndShortUrls(): iterable
{
$shortUrlWithShortCode = fn (string $shortCode, ?string $domain = null) => ShortUrl::fromMeta(
$shortUrlWithShortCode = fn (string $shortCode, ?string $domain = null) => ShortUrl::create(
ShortUrlCreation::fromRawData([
'longUrl' => '',
'customSlug' => $shortCode,

View file

@ -74,7 +74,7 @@ class ShortUrlRepositoryAdapterTest extends TestCase
$dateRange = $params->dateRange;
$this->repo->expects($this->once())->method('countList')->with(
new ShortUrlsCountFiltering($searchTerm, $tags, TagsMode::ANY, $dateRange, $apiKey),
new ShortUrlsCountFiltering($searchTerm, $tags, TagsMode::ANY, $dateRange, apiKey: $apiKey),
);
$adapter->getNbResults();
}

View file

@ -114,7 +114,7 @@ class ShortUrlResolverTest extends TestCase
$now = Chronos::now();
yield 'maxVisits reached' => [(function () {
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => '']));
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => '']));
$shortUrl->setVisits(new ArrayCollection(map(
range(0, 4),
fn () => Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()),
@ -122,14 +122,14 @@ class ShortUrlResolverTest extends TestCase
return $shortUrl;
})()];
yield 'future validSince' => [ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
yield 'future validSince' => [ShortUrl::create(ShortUrlCreation::fromRawData(
['validSince' => $now->addMonth()->toAtomString(), 'longUrl' => ''],
))];
yield 'past validUntil' => [ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
yield 'past validUntil' => [ShortUrl::create(ShortUrlCreation::fromRawData(
['validUntil' => $now->subMonth()->toAtomString(), 'longUrl' => ''],
))];
yield 'mixed' => [(function () use ($now) {
$shortUrl = ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([
'maxVisits' => 3,
'validUntil' => $now->subMonth()->toAtomString(),
'longUrl' => '',

View file

@ -43,7 +43,7 @@ class ShortUrlDataTransformerTest extends TestCase
'validUntil' => null,
'maxVisits' => null,
]];
yield 'max visits only' => [ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
yield 'max visits only' => [ShortUrl::create(ShortUrlCreation::fromRawData([
'maxVisits' => $maxVisits,
'longUrl' => '',
])), [
@ -52,7 +52,7 @@ class ShortUrlDataTransformerTest extends TestCase
'maxVisits' => $maxVisits,
]];
yield 'max visits and valid since' => [
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
ShortUrl::create(ShortUrlCreation::fromRawData(
['validSince' => $now, 'maxVisits' => $maxVisits, 'longUrl' => ''],
)),
[
@ -62,7 +62,7 @@ class ShortUrlDataTransformerTest extends TestCase
],
];
yield 'both dates' => [
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
ShortUrl::create(ShortUrlCreation::fromRawData(
['validSince' => $now, 'validUntil' => $now->subDays(10), 'longUrl' => ''],
)),
[
@ -72,7 +72,7 @@ class ShortUrlDataTransformerTest extends TestCase
],
];
yield 'everything' => [
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
ShortUrl::create(ShortUrlCreation::fromRawData(
['validSince' => $now, 'validUntil' => $now->subDays(5), 'maxVisits' => $maxVisits, 'longUrl' => ''],
)),
[

View file

@ -107,17 +107,17 @@ class UrlShortenerTest extends TestCase
), ShortUrl::withLongUrl($url)];
yield [
ShortUrlCreation::fromRawData(['findIfExists' => true, 'longUrl' => $url, 'tags' => ['foo', 'bar']]),
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['longUrl' => $url, 'tags' => ['foo', 'bar']])),
ShortUrl::create(ShortUrlCreation::fromRawData(['longUrl' => $url, 'tags' => ['foo', 'bar']])),
];
yield [
ShortUrlCreation::fromRawData(['findIfExists' => true, 'maxVisits' => 3, 'longUrl' => $url]),
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => $url])),
ShortUrl::create(ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => $url])),
];
yield [
ShortUrlCreation::fromRawData(
['findIfExists' => true, 'validSince' => Chronos::parse('2017-01-01'), 'longUrl' => $url],
),
ShortUrl::fromMeta(
ShortUrl::create(
ShortUrlCreation::fromRawData(['validSince' => Chronos::parse('2017-01-01'), 'longUrl' => $url]),
),
];
@ -125,13 +125,13 @@ class UrlShortenerTest extends TestCase
ShortUrlCreation::fromRawData(
['findIfExists' => true, 'validUntil' => Chronos::parse('2017-01-01'), 'longUrl' => $url],
),
ShortUrl::fromMeta(
ShortUrl::create(
ShortUrlCreation::fromRawData(['validUntil' => Chronos::parse('2017-01-01'), 'longUrl' => $url]),
),
];
yield [
ShortUrlCreation::fromRawData(['findIfExists' => true, 'domain' => 'example.com', 'longUrl' => $url]),
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(['domain' => 'example.com', 'longUrl' => $url])),
ShortUrl::create(ShortUrlCreation::fromRawData(['domain' => 'example.com', 'longUrl' => $url])),
];
yield [
ShortUrlCreation::fromRawData([
@ -141,7 +141,7 @@ class UrlShortenerTest extends TestCase
'longUrl' => $url,
'tags' => ['baz', 'foo', 'bar'],
]),
ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
ShortUrl::create(ShortUrlCreation::fromRawData([
'validUntil' => Chronos::parse('2017-01-01'),
'maxVisits' => 4,
'longUrl' => $url,

View file

@ -22,7 +22,7 @@ class ListShortUrlsTest extends ApiTestCase
'meta' => [
'validSince' => null,
'validUntil' => null,
'maxVisits' => null,
'maxVisits' => 2,
],
'domain' => null,
'title' => 'My cool title',
@ -38,7 +38,7 @@ class ListShortUrlsTest extends ApiTestCase
'tags' => [],
'meta' => [
'validSince' => null,
'validUntil' => null,
'validUntil' => '2020-05-01T00:00:00+00:00',
'maxVisits' => null,
],
'domain' => null,
@ -147,6 +147,20 @@ class ListShortUrlsTest extends ApiTestCase
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_DOCS,
], 'valid_api_key'];
yield [['excludePastValidUntil' => 'true'], [
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_SHLINK_WITH_TITLE,
], 'valid_api_key'];
yield [['excludeMaxVisitsReached' => 'true'], [
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_DOCS,
], 'valid_api_key'];
yield [['orderBy' => 'shortCode'], [
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_CUSTOM_SLUG,

View file

@ -29,19 +29,20 @@ class ShortUrlsFixture extends AbstractFixture implements DependentFixtureInterf
$authorApiKey = $this->getReference('author_api_key');
$abcShortUrl = $this->setShortUrlDate(
ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
ShortUrl::create(ShortUrlCreation::fromRawData([
'customSlug' => 'abc123',
'apiKey' => $authorApiKey,
'longUrl' => 'https://shlink.io',
'tags' => ['foo'],
'title' => 'My cool title',
'crawlable' => true,
'maxVisits' => 2,
]), $relationResolver),
'2018-05-01',
);
$manager->persist($abcShortUrl);
$defShortUrl = $this->setShortUrlDate(ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$defShortUrl = $this->setShortUrlDate(ShortUrl::create(ShortUrlCreation::fromRawData([
'validSince' => Chronos::parse('2020-05-01'),
'customSlug' => 'def456',
'apiKey' => $authorApiKey,
@ -51,7 +52,7 @@ class ShortUrlsFixture extends AbstractFixture implements DependentFixtureInterf
]), $relationResolver), '2019-01-01 00:00:10');
$manager->persist($defShortUrl);
$customShortUrl = $this->setShortUrlDate(ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$customShortUrl = $this->setShortUrlDate(ShortUrl::create(ShortUrlCreation::fromRawData([
'customSlug' => 'custom',
'maxVisits' => 2,
'apiKey' => $authorApiKey,
@ -61,14 +62,16 @@ class ShortUrlsFixture extends AbstractFixture implements DependentFixtureInterf
$manager->persist($customShortUrl);
$ghiShortUrl = $this->setShortUrlDate(
ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
['customSlug' => 'ghi789', 'longUrl' => 'https://shlink.io/documentation/'],
)),
ShortUrl::create(ShortUrlCreation::fromRawData([
'customSlug' => 'ghi789',
'longUrl' => 'https://shlink.io/documentation/',
'validUntil' => Chronos::parse('2020-05-01'), // In the past
])),
'2018-05-01',
);
$manager->persist($ghiShortUrl);
$withDomainDuplicatingShortCode = $this->setShortUrlDate(ShortUrl::fromMeta(ShortUrlCreation::fromRawData([
$withDomainDuplicatingShortCode = $this->setShortUrlDate(ShortUrl::create(ShortUrlCreation::fromRawData([
'domain' => 'example.com',
'customSlug' => 'ghi789',
'longUrl' => 'https://blog.alejandrocelaya.com/2019/04/27/considerations-to-properly-use-open-'
@ -77,7 +80,7 @@ class ShortUrlsFixture extends AbstractFixture implements DependentFixtureInterf
]), $relationResolver), '2019-01-01 00:00:30');
$manager->persist($withDomainDuplicatingShortCode);
$withDomainAndSlugShortUrl = $this->setShortUrlDate(ShortUrl::fromMeta(ShortUrlCreation::fromRawData(
$withDomainAndSlugShortUrl = $this->setShortUrlDate(ShortUrl::create(ShortUrlCreation::fromRawData(
['domain' => 'some-domain.com', 'customSlug' => 'custom-with-domain', 'longUrl' => 'https://google.com'],
)), '2018-10-20');
$manager->persist($withDomainAndSlugShortUrl);