mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-23 13:23:33 +03:00
Merge pull request #1622 from acelaya-forks/feature/filter-out-disabled
Feature/filter out disabled
This commit is contained in:
commit
0b04476c99
29 changed files with 296 additions and 119 deletions
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'],
|
||||
),
|
||||
|
|
|
@ -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']),
|
||||
);
|
||||
|
||||
|
|
|
@ -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],
|
||||
),
|
||||
|
|
|
@ -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' => '',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
])),
|
||||
|
|
|
@ -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' => ''],
|
||||
));
|
||||
|
||||
|
|
|
@ -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,
|
||||
]));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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' => '',
|
||||
|
|
|
@ -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' => ''],
|
||||
)),
|
||||
[
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue