mirror of
https://github.com/shlinkio/shlink.git
synced 2025-02-04 01:20:53 +03:00
Added nullsafe operator to simplify conditions
This commit is contained in:
parent
e0f0bb5523
commit
c01121d61a
64 changed files with 95 additions and 113 deletions
|
@ -58,7 +58,7 @@ class ListKeysCommand extends BaseCommand
|
|||
if (! $enabledOnly) {
|
||||
$rowData[] = sprintf($messagePattern, $this->getEnabledSymbol($apiKey));
|
||||
}
|
||||
$rowData[] = $expiration !== null ? $expiration->toAtomString() : '-';
|
||||
$rowData[] = $expiration?->toAtomString() ?? '-';
|
||||
$rowData[] = $apiKey->isAdmin() ? 'Admin' : implode("\n", $apiKey->mapRoles(
|
||||
fn (string $roleName, array $meta) =>
|
||||
empty($meta)
|
||||
|
|
|
@ -22,7 +22,7 @@ abstract class BaseCommand extends Command
|
|||
?string $shortcut = null,
|
||||
?int $mode = null,
|
||||
string $description = '',
|
||||
$default = null
|
||||
$default = null,
|
||||
): self {
|
||||
$this->addOption($name, $shortcut, $mode, $description, $default);
|
||||
|
||||
|
|
|
@ -126,8 +126,8 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
|
|||
ShortUrlsParamsInputFilter::SEARCH_TERM => $searchTerm,
|
||||
ShortUrlsParamsInputFilter::TAGS => $tags,
|
||||
ShortUrlsOrdering::ORDER_BY => $orderBy,
|
||||
ShortUrlsParamsInputFilter::START_DATE => $startDate !== null ? $startDate->toAtomString() : null,
|
||||
ShortUrlsParamsInputFilter::END_DATE => $endDate !== null ? $endDate->toAtomString() : null,
|
||||
ShortUrlsParamsInputFilter::START_DATE => $startDate?->toAtomString(),
|
||||
ShortUrlsParamsInputFilter::END_DATE => $endDate?->toAtomString(),
|
||||
];
|
||||
|
||||
if ($all) {
|
||||
|
@ -155,7 +155,7 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
|
|||
OutputInterface $output,
|
||||
array $columnsMap,
|
||||
ShortUrlsParams $params,
|
||||
bool $all
|
||||
bool $all,
|
||||
): Paginator {
|
||||
$shortUrls = $this->shortUrlService->listShortUrls($params);
|
||||
|
||||
|
@ -200,14 +200,11 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
|
|||
}
|
||||
if ($input->getOption('show-api-key')) {
|
||||
$columnsMap['API Key'] = static fn (array $_, ShortUrl $shortUrl): string =>
|
||||
(string) $shortUrl->authorApiKey();
|
||||
(string) $shortUrl->authorApiKey();
|
||||
}
|
||||
if ($input->getOption('show-api-key-name')) {
|
||||
$columnsMap['API Key Name'] = static function (array $_, ShortUrl $shortUrl): ?string {
|
||||
$apiKey = $shortUrl->authorApiKey();
|
||||
|
||||
return $apiKey !== null ? $apiKey->name() : null;
|
||||
};
|
||||
$columnsMap['API Key Name'] = static fn (array $_, ShortUrl $shortUrl): ?string =>
|
||||
$shortUrl->authorApiKey()?->name();
|
||||
}
|
||||
|
||||
return $columnsMap;
|
||||
|
|
|
@ -33,7 +33,7 @@ class RoleResolverTest extends TestCase
|
|||
public function properRolesAreResolvedBasedOnInput(
|
||||
InputInterface $input,
|
||||
array $expectedRoles,
|
||||
int $expectedDomainCalls
|
||||
int $expectedDomainCalls,
|
||||
): void {
|
||||
$getDomain = $this->domainService->getOrCreate('example.com')->willReturn(
|
||||
(new Domain('example.com'))->setId('1'),
|
||||
|
|
|
@ -74,7 +74,7 @@ class DeleteShortUrlCommandTest extends TestCase
|
|||
public function deleteIsRetriedWhenThresholdIsReachedAndQuestionIsAccepted(
|
||||
array $retryAnswer,
|
||||
int $expectedDeleteCalls,
|
||||
string $expectedMessage
|
||||
string $expectedMessage,
|
||||
): void {
|
||||
$shortCode = 'abc123';
|
||||
$identifier = new ShortUrlIdentifier($shortCode);
|
||||
|
|
|
@ -110,7 +110,7 @@ class ListShortUrlsCommandTest extends TestCase
|
|||
array $input,
|
||||
array $expectedContents,
|
||||
array $notExpectedContents,
|
||||
ApiKey $apiKey
|
||||
ApiKey $apiKey,
|
||||
): void {
|
||||
$this->shortUrlService->listShortUrls(ShortUrlsParams::emptyInstance())
|
||||
->willReturn(new Paginator(new ArrayAdapter([
|
||||
|
@ -185,7 +185,7 @@ class ListShortUrlsCommandTest extends TestCase
|
|||
?string $searchTerm,
|
||||
array $tags,
|
||||
?string $startDate = null,
|
||||
?string $endDate = null
|
||||
?string $endDate = null,
|
||||
): void {
|
||||
$listShortUrls = $this->shortUrlService->listShortUrls(ShortUrlsParams::fromRawData([
|
||||
'page' => $page,
|
||||
|
|
|
@ -36,7 +36,7 @@ class DownloadGeoLiteDbCommandTest extends TestCase
|
|||
public function showsProperMessageWhenGeoLiteUpdateFails(
|
||||
bool $olderDbExists,
|
||||
string $expectedMessage,
|
||||
int $expectedExitCode
|
||||
int $expectedExitCode,
|
||||
): void {
|
||||
$checkDbUpdate = $this->dbUpdater->checkDbUpdate(Argument::cetera())->will(
|
||||
function (array $args) use ($olderDbExists): void {
|
||||
|
|
|
@ -73,7 +73,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||
int $expectedEmptyCalls,
|
||||
int $expectedAllCalls,
|
||||
bool $expectWarningPrint,
|
||||
array $args
|
||||
array $args,
|
||||
): void {
|
||||
$visit = Visit::forValidShortUrl(ShortUrl::createEmpty(), new Visitor('', '', '1.2.3.4', ''));
|
||||
$location = VisitLocation::fromGeolocation(Location::emptyInstance());
|
||||
|
|
|
@ -84,6 +84,6 @@ abstract class AbstractTrackingAction implements MiddlewareInterface, RequestMet
|
|||
|
||||
abstract protected function createErrorResp(
|
||||
ServerRequestInterface $request,
|
||||
RequestHandlerInterface $handler
|
||||
RequestHandlerInterface $handler,
|
||||
): ResponseInterface;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class PixelAction extends AbstractTrackingAction
|
|||
|
||||
protected function createErrorResp(
|
||||
ServerRequestInterface $request,
|
||||
RequestHandlerInterface $handler
|
||||
RequestHandlerInterface $handler,
|
||||
): ResponseInterface {
|
||||
return new PixelResponse();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class DomainService implements DomainServiceInterface
|
|||
$domains = $repo->findDomainsWithout($this->defaultDomain, $apiKey);
|
||||
$mappedDomains = map($domains, fn (Domain $domain) => new DomainItem($domain->getAuthority(), false));
|
||||
|
||||
if ($apiKey !== null && $apiKey->hasRole(Role::DOMAIN_SPECIFIC)) {
|
||||
if ($apiKey?->hasRole(Role::DOMAIN_SPECIFIC)) {
|
||||
return $mappedDomains;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class ShortUrl extends AbstractEntity
|
|||
|
||||
public static function fromMeta(
|
||||
ShortUrlMeta $meta,
|
||||
?ShortUrlRelationResolverInterface $relationResolver = null
|
||||
?ShortUrlRelationResolverInterface $relationResolver = null,
|
||||
): self {
|
||||
$instance = new self();
|
||||
$relationResolver = $relationResolver ?? new SimpleShortUrlRelationResolver();
|
||||
|
@ -87,7 +87,7 @@ class ShortUrl extends AbstractEntity
|
|||
public static function fromImport(
|
||||
ImportedShlinkUrl $url,
|
||||
bool $importShortCode,
|
||||
?ShortUrlRelationResolverInterface $relationResolver = null
|
||||
?ShortUrlRelationResolverInterface $relationResolver = null,
|
||||
): self {
|
||||
$meta = [
|
||||
ShortUrlInputFilter::VALIDATE_URL => false,
|
||||
|
@ -209,7 +209,7 @@ class ShortUrl extends AbstractEntity
|
|||
|
||||
public function update(
|
||||
ShortUrlEdit $shortUrlEdit,
|
||||
?ShortUrlRelationResolverInterface $relationResolver = null
|
||||
?ShortUrlRelationResolverInterface $relationResolver = null,
|
||||
): void {
|
||||
if ($shortUrlEdit->validSinceWasProvided()) {
|
||||
$this->validSince = $shortUrlEdit->validSince();
|
||||
|
|
|
@ -12,7 +12,7 @@ class CloseDbConnectionEventListenerDelegator
|
|||
public function __invoke(
|
||||
ContainerInterface $container,
|
||||
string $name,
|
||||
callable $callback
|
||||
callable $callback,
|
||||
): CloseDbConnectionEventListener {
|
||||
/** @var callable $wrapped */
|
||||
$wrapped = $callback();
|
||||
|
|
|
@ -69,7 +69,7 @@ class ImportedLinksProcessor implements ImportedLinksProcessorInterface
|
|||
private function resolveShortUrl(
|
||||
ImportedShlinkUrl $importedUrl,
|
||||
bool $importShortCodes,
|
||||
callable $skipOnShortCodeConflict
|
||||
callable $skipOnShortCodeConflict,
|
||||
): ShortUrlImporting {
|
||||
$alreadyImportedShortUrl = $this->shortUrlRepo->findOneByImportedUrl($importedUrl);
|
||||
if ($alreadyImportedShortUrl !== null) {
|
||||
|
@ -88,7 +88,7 @@ class ImportedLinksProcessor implements ImportedLinksProcessorInterface
|
|||
private function handleShortCodeUniqueness(
|
||||
ShortUrl $shortUrl,
|
||||
bool $importShortCodes,
|
||||
callable $skipOnShortCodeConflict
|
||||
callable $skipOnShortCodeConflict,
|
||||
): bool {
|
||||
if ($this->shortCodeHelper->ensureShortCodeUniqueness($shortUrl, $importShortCodes)) {
|
||||
return true;
|
||||
|
|
|
@ -38,10 +38,7 @@ final class ShortUrlImporting
|
|||
$importedVisits = 0;
|
||||
foreach ($visits as $importedVisit) {
|
||||
// Skip visits which are older than the most recent already imported visit's date
|
||||
if (
|
||||
$mostRecentImportedDate !== null
|
||||
&& $mostRecentImportedDate->gte(Chronos::instance($importedVisit->date()))
|
||||
) {
|
||||
if ($mostRecentImportedDate?->gte(Chronos::instance($importedVisit->date()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ final class ShortUrlIdentifier
|
|||
public static function fromShortUrl(ShortUrl $shortUrl): self
|
||||
{
|
||||
$domain = $shortUrl->getDomain();
|
||||
$domainAuthority = $domain !== null ? $domain->getAuthority() : null;
|
||||
$domainAuthority = $domain?->getAuthority();
|
||||
|
||||
return new self($shortUrl->getShortCode(), $domainAuthority);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shlinkio\Shlink\Core\Paginator\Adapter;
|
||||
|
||||
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||
use Pagerfanta\Adapter\AdapterInterface;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
|
||||
|
@ -28,7 +27,7 @@ class ShortUrlRepositoryAdapter implements AdapterInterface
|
|||
$this->params->tags(),
|
||||
$this->params->orderBy(),
|
||||
$this->params->dateRange(),
|
||||
$this->resolveSpec(),
|
||||
$this->apiKey?->spec(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -38,12 +37,7 @@ class ShortUrlRepositoryAdapter implements AdapterInterface
|
|||
$this->params->searchTerm(),
|
||||
$this->params->tags(),
|
||||
$this->params->dateRange(),
|
||||
$this->resolveSpec(),
|
||||
$this->apiKey?->spec(),
|
||||
);
|
||||
}
|
||||
|
||||
private function resolveSpec(): ?Specification
|
||||
{
|
||||
return $this->apiKey !== null ? $this->apiKey->spec() : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shlinkio\Shlink\Core\Paginator\Adapter;
|
||||
|
||||
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||
use Shlinkio\Shlink\Core\Model\VisitsParams;
|
||||
use Shlinkio\Shlink\Core\Repository\VisitRepositoryInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
|
||||
|
@ -28,7 +27,7 @@ class VisitsForTagPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
|
|||
new VisitsListFiltering(
|
||||
$this->params->getDateRange(),
|
||||
$this->params->excludeBots(),
|
||||
$this->resolveSpec(),
|
||||
$this->apiKey?->spec(true),
|
||||
$length,
|
||||
$offset,
|
||||
),
|
||||
|
@ -42,13 +41,8 @@ class VisitsForTagPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
|
|||
new VisitsCountFiltering(
|
||||
$this->params->getDateRange(),
|
||||
$this->params->excludeBots(),
|
||||
$this->resolveSpec(),
|
||||
$this->apiKey?->spec(true),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private function resolveSpec(): ?Specification
|
||||
{
|
||||
return $this->apiKey !== null ? $this->apiKey->spec(true) : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||
array $tags = [],
|
||||
?ShortUrlsOrdering $orderBy = null,
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null
|
||||
?Specification $spec = null,
|
||||
): array {
|
||||
$qb = $this->createListQueryBuilder($searchTerm, $tags, $dateRange, $spec);
|
||||
$qb->select('DISTINCT s')
|
||||
|
@ -43,7 +43,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||
->setFirstResult($offset);
|
||||
|
||||
// In case the ordering has been specified, the query could be more complex. Process it
|
||||
if ($orderBy !== null && $orderBy->hasOrderField()) {
|
||||
if ($orderBy?->hasOrderField()) {
|
||||
return $this->processOrderByForList($qb, $orderBy);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null
|
||||
?Specification $spec = null,
|
||||
): int {
|
||||
$qb = $this->createListQueryBuilder($searchTerm, $tags, $dateRange, $spec);
|
||||
$qb->select('COUNT(DISTINCT s)');
|
||||
|
@ -97,17 +97,17 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||
?string $searchTerm,
|
||||
array $tags,
|
||||
?DateRange $dateRange,
|
||||
?Specification $spec
|
||||
?Specification $spec,
|
||||
): QueryBuilder {
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
$qb->from(ShortUrl::class, 's')
|
||||
->where('1=1');
|
||||
|
||||
if ($dateRange !== null && $dateRange->getStartDate() !== null) {
|
||||
if ($dateRange?->getStartDate() !== null) {
|
||||
$qb->andWhere($qb->expr()->gte('s.dateCreated', ':startDate'));
|
||||
$qb->setParameter('startDate', $dateRange->getStartDate(), ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
}
|
||||
if ($dateRange !== null && $dateRange->getEndDate() !== null) {
|
||||
if ($dateRange?->getEndDate() !== null) {
|
||||
$qb->andWhere($qb->expr()->lte('s.dateCreated', ':endDate'));
|
||||
$qb->setParameter('endDate', $dateRange->getEndDate(), ChronosDateTimeType::CHRONOS_DATETIME);
|
||||
}
|
||||
|
|
|
@ -23,14 +23,14 @@ interface ShortUrlRepositoryInterface extends ObjectRepository, EntitySpecificat
|
|||
array $tags = [],
|
||||
?ShortUrlsOrdering $orderBy = null,
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null
|
||||
?Specification $spec = null,
|
||||
): array;
|
||||
|
||||
public function countList(
|
||||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?DateRange $dateRange = null,
|
||||
?Specification $spec = null
|
||||
?Specification $spec = null,
|
||||
): int;
|
||||
|
||||
public function findOneWithDomainFallback(string $shortCode, ?string $domain = null): ?ShortUrl;
|
||||
|
|
|
@ -71,14 +71,14 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
|||
$iterator = $qb->getQuery()->toIterable();
|
||||
$resultsFound = false;
|
||||
|
||||
/** @var Visit $visit */
|
||||
foreach ($iterator as $key => $visit) {
|
||||
$resultsFound = true;
|
||||
yield $key => $visit;
|
||||
}
|
||||
|
||||
// As the query is ordered by ID, we can take the last one every time in order to exclude the whole list
|
||||
$lastId = isset($visit) ? $visit->getId() : $lastId;
|
||||
/** @var Visit|null $visit */
|
||||
$lastId = $visit?->getId() ?? $lastId;
|
||||
} while ($resultsFound);
|
||||
}
|
||||
|
||||
|
@ -101,12 +101,12 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
|||
|
||||
private function createVisitsByShortCodeQueryBuilder(
|
||||
ShortUrlIdentifier $identifier,
|
||||
VisitsCountFiltering $filtering
|
||||
VisitsCountFiltering $filtering,
|
||||
): QueryBuilder {
|
||||
/** @var ShortUrlRepositoryInterface $shortUrlRepo */
|
||||
$shortUrlRepo = $this->getEntityManager()->getRepository(ShortUrl::class);
|
||||
$shortUrl = $shortUrlRepo->findOne($identifier, $filtering->spec());
|
||||
$shortUrlId = $shortUrl !== null ? $shortUrl->getId() : -1;
|
||||
$shortUrlId = $shortUrl?->getId() ?? '-1';
|
||||
|
||||
// Parameters in this query need to be part of the query itself, as we need to use it a sub-query later
|
||||
// Since they are not strictly provided by the caller, it's reasonably safe
|
||||
|
@ -187,10 +187,10 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
|
|||
|
||||
private function applyDatesInline(QueryBuilder $qb, ?DateRange $dateRange): void
|
||||
{
|
||||
if ($dateRange !== null && $dateRange->getStartDate() !== null) {
|
||||
if ($dateRange?->getStartDate() !== null) {
|
||||
$qb->andWhere($qb->expr()->gte('v.date', '\'' . $dateRange->getStartDate()->toDateTimeString() . '\''));
|
||||
}
|
||||
if ($dateRange !== null && $dateRange->getEndDate() !== null) {
|
||||
if ($dateRange?->getEndDate() !== null) {
|
||||
$qb->andWhere($qb->expr()->lte('v.date', '\'' . $dateRange->getEndDate()->toDateTimeString() . '\''));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class DeleteShortUrlService implements DeleteShortUrlServiceInterface
|
|||
public function deleteByShortCode(
|
||||
ShortUrlIdentifier $identifier,
|
||||
bool $ignoreThreshold = false,
|
||||
?ApiKey $apiKey = null
|
||||
?ApiKey $apiKey = null,
|
||||
): void {
|
||||
$shortUrl = $this->urlResolver->resolveShortUrl($identifier, $apiKey);
|
||||
if (! $ignoreThreshold && $this->isThresholdReached($shortUrl)) {
|
||||
|
|
|
@ -17,6 +17,6 @@ interface DeleteShortUrlServiceInterface
|
|||
public function deleteByShortCode(
|
||||
ShortUrlIdentifier $identifier,
|
||||
bool $ignoreThreshold = false,
|
||||
?ApiKey $apiKey = null
|
||||
?ApiKey $apiKey = null,
|
||||
): void;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class ShortUrlResolver implements ShortUrlResolverInterface
|
|||
{
|
||||
/** @var ShortUrlRepository $shortUrlRepo */
|
||||
$shortUrlRepo = $this->em->getRepository(ShortUrl::class);
|
||||
$shortUrl = $shortUrlRepo->findOne($identifier, $apiKey !== null ? $apiKey->spec() : null);
|
||||
$shortUrl = $shortUrlRepo->findOne($identifier, $apiKey?->spec());
|
||||
if ($shortUrl === null) {
|
||||
throw ShortUrlNotFoundException::fromNotFound($identifier);
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ class ShortUrlResolver implements ShortUrlResolverInterface
|
|||
/** @var ShortUrlRepository $shortUrlRepo */
|
||||
$shortUrlRepo = $this->em->getRepository(ShortUrl::class);
|
||||
$shortUrl = $shortUrlRepo->findOneWithDomainFallback($identifier->shortCode(), $identifier->domain());
|
||||
if ($shortUrl === null || ! $shortUrl->isEnabled()) {
|
||||
if (! $shortUrl?->isEnabled()) {
|
||||
throw ShortUrlNotFoundException::fromNotFound($identifier);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class ShortUrlService implements ShortUrlServiceInterface
|
|||
public function updateShortUrl(
|
||||
ShortUrlIdentifier $identifier,
|
||||
ShortUrlEdit $shortUrlEdit,
|
||||
?ApiKey $apiKey = null
|
||||
?ApiKey $apiKey = null,
|
||||
): ShortUrl {
|
||||
if ($shortUrlEdit->longUrlWasProvided()) {
|
||||
/** @var ShortUrlEdit $shortUrlEdit */
|
||||
|
|
|
@ -27,6 +27,6 @@ interface ShortUrlServiceInterface
|
|||
public function updateShortUrl(
|
||||
ShortUrlIdentifier $identifier,
|
||||
ShortUrlEdit $shortUrlEdit,
|
||||
?ApiKey $apiKey = null
|
||||
?ApiKey $apiKey = null,
|
||||
): ShortUrl;
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class UrlShortener implements UrlShortenerInterface
|
|||
|
||||
if (! $couldBeMadeUnique) {
|
||||
$domain = $shortUrlToBeCreated->getDomain();
|
||||
$domainAuthority = $domain !== null ? $domain->getAuthority() : null;
|
||||
$domainAuthority = $domain?->getAuthority();
|
||||
|
||||
throw NonUniqueSlugException::fromSlug($shortUrlToBeCreated->getShortCode(), $domainAuthority);
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ class InDateRange extends BaseSpecification
|
|||
{
|
||||
$criteria = [];
|
||||
|
||||
if ($this->dateRange !== null && $this->dateRange->getStartDate() !== null) {
|
||||
if ($this->dateRange?->getStartDate() !== null) {
|
||||
$criteria[] = Spec::gte($this->field, $this->dateRange->getStartDate()->toDateTimeString());
|
||||
}
|
||||
|
||||
if ($this->dateRange !== null && $this->dateRange->getEndDate() !== null) {
|
||||
if ($this->dateRange?->getEndDate() !== null) {
|
||||
$criteria[] = Spec::lte($this->field, $this->dateRange->getEndDate()->toDateTimeString());
|
||||
}
|
||||
|
||||
|
|
|
@ -49,9 +49,9 @@ class VisitsStatsHelper implements VisitsStatsHelperInterface
|
|||
public function visitsForShortUrl(
|
||||
ShortUrlIdentifier $identifier,
|
||||
VisitsParams $params,
|
||||
?ApiKey $apiKey = null
|
||||
?ApiKey $apiKey = null,
|
||||
): Paginator {
|
||||
$spec = $apiKey !== null ? $apiKey->spec() : null;
|
||||
$spec = $apiKey?->spec();
|
||||
|
||||
/** @var ShortUrlRepositoryInterface $repo */
|
||||
$repo = $this->em->getRepository(ShortUrl::class);
|
||||
|
|
|
@ -24,7 +24,7 @@ interface VisitsStatsHelperInterface
|
|||
public function visitsForShortUrl(
|
||||
ShortUrlIdentifier $identifier,
|
||||
VisitsParams $params,
|
||||
?ApiKey $apiKey = null
|
||||
?ApiKey $apiKey = null,
|
||||
): Paginator;
|
||||
|
||||
/**
|
||||
|
|
|
@ -84,7 +84,7 @@ class QrCodeActionTest extends TestCase
|
|||
*/
|
||||
public function imageIsReturnedWithExpectedContentTypeBasedOnProvidedFormat(
|
||||
array $query,
|
||||
string $expectedContentType
|
||||
string $expectedContentType,
|
||||
): void {
|
||||
$code = 'abc123';
|
||||
$this->urlResolver->resolveEnabledShortUrl(new ShortUrlIdentifier($code, ''))->willReturn(
|
||||
|
|
|
@ -24,7 +24,7 @@ class BasePathPrefixerTest extends TestCase
|
|||
array $originalConfig,
|
||||
array $expectedRoutes,
|
||||
array $expectedMiddlewares,
|
||||
string $expectedHostname
|
||||
string $expectedHostname,
|
||||
): void {
|
||||
[
|
||||
'routes' => $routes,
|
||||
|
|
|
@ -126,7 +126,7 @@ class DomainServiceTest extends TestCase
|
|||
$repo = $this->prophesize(DomainRepositoryInterface::class);
|
||||
$repo->findOneBy(['authority' => $authority])->willReturn($foundDomain);
|
||||
$getRepo = $this->em->getRepository(Domain::class)->willReturn($repo->reveal());
|
||||
$persist = $this->em->persist($foundDomain !== null ? $foundDomain : Argument::type(Domain::class));
|
||||
$persist = $this->em->persist($foundDomain ?? Argument::type(Domain::class));
|
||||
$flush = $this->em->flush();
|
||||
|
||||
$result = $this->domainService->getOrCreate($authority);
|
||||
|
|
|
@ -26,7 +26,7 @@ class ShortUrlTest extends TestCase
|
|||
*/
|
||||
public function regenerateShortCodeThrowsExceptionIfStateIsInvalid(
|
||||
ShortUrl $shortUrl,
|
||||
string $expectedMessage
|
||||
string $expectedMessage,
|
||||
): void {
|
||||
$this->expectException(ShortCodeCannotBeRegeneratedException::class);
|
||||
$this->expectExceptionMessage($expectedMessage);
|
||||
|
|
|
@ -43,7 +43,7 @@ class NotFoundRedirectHandlerTest extends TestCase
|
|||
*/
|
||||
public function expectedRedirectionIsReturnedDependingOnTheCase(
|
||||
ServerRequestInterface $request,
|
||||
string $expectedRedirectTo
|
||||
string $expectedRedirectTo,
|
||||
): void {
|
||||
$this->redirectOptions->invalidShortUrl = 'invalidShortUrl';
|
||||
$this->redirectOptions->regular404 = 'regular404';
|
||||
|
|
|
@ -79,7 +79,7 @@ class UpdateGeoLiteDbTest extends TestCase
|
|||
int $total,
|
||||
int $downloaded,
|
||||
bool $oldDbExists,
|
||||
?string $expectedMessage
|
||||
?string $expectedMessage,
|
||||
): void {
|
||||
$checkDbUpdate = $this->dbUpdater->checkDbUpdate(Argument::cetera())->will(
|
||||
function (array $args) use ($total, $downloaded, $oldDbExists): void {
|
||||
|
|
|
@ -21,7 +21,7 @@ class DeleteShortUrlExceptionTest extends TestCase
|
|||
public function fromVisitsThresholdGeneratesMessageProperly(
|
||||
int $threshold,
|
||||
string $shortCode,
|
||||
string $expectedMessage
|
||||
string $expectedMessage,
|
||||
): void {
|
||||
$e = DeleteShortUrlException::fromVisitsThreshold($threshold, $shortCode);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class ForbiddenTagOperationExceptionTest extends TestCase
|
|||
*/
|
||||
public function createsExpectedExceptionForDeletion(
|
||||
ForbiddenTagOperationException $e,
|
||||
string $expectedMessage
|
||||
string $expectedMessage,
|
||||
): void {
|
||||
$this->assertExceptionShape($e, $expectedMessage);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ class ShortUrlNotFoundExceptionTest extends TestCase
|
|||
public function properlyCreatesExceptionFromNotFoundShortCode(
|
||||
string $expectedMessage,
|
||||
string $shortCode,
|
||||
?string $domain
|
||||
?string $domain,
|
||||
): void {
|
||||
$expectedAdditional = ['shortCode' => $shortCode];
|
||||
if ($domain !== null) {
|
||||
|
|
|
@ -160,7 +160,7 @@ class ImportedLinksProcessorTest extends TestCase
|
|||
ImportedShlinkUrl $importedUrl,
|
||||
string $expectedOutput,
|
||||
int $amountOfPersistedVisits,
|
||||
?ShortUrl $foundShortUrl
|
||||
?ShortUrl $foundShortUrl,
|
||||
): void {
|
||||
$findExisting = $this->repo->findOneByImportedUrl(Argument::cetera())->willReturn($foundShortUrl);
|
||||
$ensureUniqueness = $this->shortCodeHelper->ensureShortCodeUniqueness(Argument::cetera())->willReturn(true);
|
||||
|
|
|
@ -33,7 +33,7 @@ class ShortUrlRepositoryAdapterTest extends TestCase
|
|||
array $tags = [],
|
||||
?string $startDate = null,
|
||||
?string $endDate = null,
|
||||
?string $orderBy = null
|
||||
?string $orderBy = null,
|
||||
): void {
|
||||
$params = ShortUrlsParams::fromRawData([
|
||||
'searchTerm' => $searchTerm,
|
||||
|
@ -58,7 +58,7 @@ class ShortUrlRepositoryAdapterTest extends TestCase
|
|||
?string $searchTerm = null,
|
||||
array $tags = [],
|
||||
?string $startDate = null,
|
||||
?string $endDate = null
|
||||
?string $endDate = null,
|
||||
): void {
|
||||
$params = ShortUrlsParams::fromRawData([
|
||||
'searchTerm' => $searchTerm,
|
||||
|
|
|
@ -70,7 +70,7 @@ class VisitsPaginatorAdapterTest extends TestCase
|
|||
$this->repo->reveal(),
|
||||
new ShortUrlIdentifier(''),
|
||||
VisitsParams::fromRawData([]),
|
||||
$apiKey !== null ? $apiKey->spec() : null,
|
||||
$apiKey?->spec(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class ShortUrlResolverTest extends TestCase
|
|||
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
|
||||
|
||||
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
||||
$findOne = $repo->findOne($identifier, $apiKey !== null ? $apiKey->spec() : null)->willReturn($shortUrl);
|
||||
$findOne = $repo->findOne($identifier, $apiKey?->spec())->willReturn($shortUrl);
|
||||
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
||||
|
||||
$result = $this->urlResolver->resolveShortUrl($identifier, $apiKey);
|
||||
|
@ -69,7 +69,7 @@ class ShortUrlResolverTest extends TestCase
|
|||
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
|
||||
|
||||
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
||||
$findOne = $repo->findOne($identifier, $apiKey !== null ? $apiKey->spec() : null)->willReturn(null);
|
||||
$findOne = $repo->findOne($identifier, $apiKey?->spec())->willReturn(null);
|
||||
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal(), $apiKey);
|
||||
|
||||
$this->expectException(ShortUrlNotFoundException::class);
|
||||
|
|
|
@ -82,7 +82,7 @@ class ShortUrlServiceTest extends TestCase
|
|||
public function updateShortUrlUpdatesProvidedData(
|
||||
int $expectedValidateCalls,
|
||||
ShortUrlEdit $shortUrlEdit,
|
||||
?ApiKey $apiKey
|
||||
?ApiKey $apiKey,
|
||||
): void {
|
||||
$originalLongUrl = 'originalLongUrl';
|
||||
$shortUrl = ShortUrl::withLongUrl($originalLongUrl);
|
||||
|
|
|
@ -19,7 +19,7 @@ class ShortUrlStringifierTest extends TestCase
|
|||
array $config,
|
||||
string $basePath,
|
||||
ShortUrl $shortUrl,
|
||||
string $expected
|
||||
string $expected,
|
||||
): void {
|
||||
$stringifier = new ShortUrlStringifier($config, $basePath);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class DoctrineBatchHelperTest extends TestCase
|
|||
public function entityManagerIsFlushedAndClearedTheExpectedAmountOfTimes(
|
||||
array $iterable,
|
||||
int $batchSize,
|
||||
int $expectedCalls
|
||||
int $expectedCalls,
|
||||
): void {
|
||||
$wrappedIterable = $this->helper->wrapIterable($iterable, $batchSize);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class RedirectResponseHelperTest extends TestCase
|
|||
int $configuredStatus,
|
||||
int $configuredLifetime,
|
||||
int $expectedStatus,
|
||||
?string $expectedCacheControl
|
||||
?string $expectedCacheControl,
|
||||
): void {
|
||||
$this->shortenerOpts->redirectStatusCode = $configuredStatus;
|
||||
$this->shortenerOpts->redirectCacheLifetime = $configuredLifetime;
|
||||
|
|
|
@ -90,7 +90,7 @@ class UrlValidatorTest extends TestCase
|
|||
*/
|
||||
public function validateUrlWithTitleReturnsNullWhenRequestFailsAndValidationIsDisabled(
|
||||
?bool $doValidate,
|
||||
bool $validateUrl
|
||||
bool $validateUrl,
|
||||
): void {
|
||||
$request = $this->httpClient->request(Argument::cetera())->willThrow(ClientException::class);
|
||||
$this->options->validateUrl = $validateUrl;
|
||||
|
|
|
@ -53,7 +53,7 @@ class VisitLocatorTest extends TestCase
|
|||
*/
|
||||
public function locateVisitsIteratesAndLocatesExpectedVisits(
|
||||
string $serviceMethodName,
|
||||
string $expectedRepoMethodName
|
||||
string $expectedRepoMethodName,
|
||||
): void {
|
||||
$unlocatedVisits = map(
|
||||
range(1, 200),
|
||||
|
@ -105,7 +105,7 @@ class VisitLocatorTest extends TestCase
|
|||
public function visitsWhichCannotBeLocatedAreIgnoredOrLocatedAsEmpty(
|
||||
string $serviceMethodName,
|
||||
string $expectedRepoMethodName,
|
||||
bool $isNonLocatableAddress
|
||||
bool $isNonLocatableAddress,
|
||||
): void {
|
||||
$unlocatedVisits = [
|
||||
Visit::forValidShortUrl(ShortUrl::withLongUrl('foo'), Visitor::emptyInstance()),
|
||||
|
|
|
@ -80,7 +80,7 @@ class VisitsStatsHelperTest extends TestCase
|
|||
{
|
||||
$shortCode = '123ABC';
|
||||
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain($shortCode);
|
||||
$spec = $apiKey === null ? null : $apiKey->spec();
|
||||
$spec = $apiKey?->spec();
|
||||
|
||||
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
||||
$count = $repo->shortCodeIsInUse($identifier, $spec)->willReturn(
|
||||
|
|
|
@ -116,7 +116,7 @@ class ApiKey extends AbstractEntity
|
|||
{
|
||||
/** @var ApiKeyRole|null $role */
|
||||
$role = $this->roles->get($roleName);
|
||||
return $role === null ? [] : $role->meta();
|
||||
return $role?->meta() ?? [];
|
||||
}
|
||||
|
||||
public function mapRoles(callable $fun): array
|
||||
|
|
|
@ -22,7 +22,7 @@ class ApiKeyService implements ApiKeyServiceInterface
|
|||
public function create(
|
||||
?Chronos $expirationDate = null,
|
||||
?string $name = null,
|
||||
RoleDefinition ...$roleDefinitions
|
||||
RoleDefinition ...$roleDefinitions,
|
||||
): ApiKey {
|
||||
$key = $this->buildApiKeyWithParams($expirationDate, $name);
|
||||
foreach ($roleDefinitions as $definition) {
|
||||
|
|
|
@ -14,7 +14,7 @@ interface ApiKeyServiceInterface
|
|||
public function create(
|
||||
?Chronos $expirationDate = null,
|
||||
?string $name = null,
|
||||
RoleDefinition ...$roleDefinitions
|
||||
RoleDefinition ...$roleDefinitions,
|
||||
): ApiKey;
|
||||
|
||||
public function check(string $key): ApiKeyCheckResult;
|
||||
|
|
|
@ -19,7 +19,7 @@ class DeleteShortUrlTest extends ApiTestCase
|
|||
string $shortCode,
|
||||
?string $domain,
|
||||
string $expectedDetail,
|
||||
string $apiKey
|
||||
string $apiKey,
|
||||
): void {
|
||||
$resp = $this->callApiWithKey(self::METHOD_DELETE, $this->buildShortUrlPath($shortCode, $domain), [], $apiKey);
|
||||
$payload = $this->getJsonResponsePayload($resp);
|
||||
|
|
|
@ -35,7 +35,7 @@ class EditShortUrlTagsTest extends ApiTestCase
|
|||
string $shortCode,
|
||||
?string $domain,
|
||||
string $expectedDetail,
|
||||
string $apiKey
|
||||
string $apiKey,
|
||||
): void {
|
||||
$url = $this->buildShortUrlPath($shortCode, $domain, '/tags');
|
||||
$resp = $this->callApiWithKey(self::METHOD_PUT, $url, [RequestOptions::JSON => [
|
||||
|
|
|
@ -6,12 +6,12 @@ namespace ShlinkioApiTest\Shlink\Rest\Action;
|
|||
|
||||
use Cake\Chronos\Chronos;
|
||||
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
|
||||
use GuzzleHttp\Psr7\Query;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use Laminas\Diactoros\Uri;
|
||||
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
|
||||
use ShlinkioApiTest\Shlink\Rest\Utils\NotFoundUrlHelpersTrait;
|
||||
|
||||
use function GuzzleHttp\Psr7\build_query;
|
||||
use function sprintf;
|
||||
|
||||
class EditShortUrlTest extends ApiTestCase
|
||||
|
@ -105,7 +105,7 @@ class EditShortUrlTest extends ApiTestCase
|
|||
string $shortCode,
|
||||
?string $domain,
|
||||
string $expectedDetail,
|
||||
string $apiKey
|
||||
string $apiKey,
|
||||
): void {
|
||||
$url = $this->buildShortUrlPath($shortCode, $domain);
|
||||
$resp = $this->callApiWithKey(self::METHOD_PATCH, $url, [RequestOptions::JSON => []], $apiKey);
|
||||
|
@ -147,7 +147,7 @@ class EditShortUrlTest extends ApiTestCase
|
|||
$url = new Uri(sprintf('/short-urls/%s', $shortCode));
|
||||
|
||||
if ($domain !== null) {
|
||||
$url = $url->withQuery(build_query(['domain' => $domain]));
|
||||
$url = $url->withQuery(Query::build(['domain' => $domain]));
|
||||
}
|
||||
|
||||
$editResp = $this->callApiWithKey(self::METHOD_PATCH, (string) $url, [RequestOptions::JSON => [
|
||||
|
|
|
@ -45,7 +45,7 @@ class OrphanVisitsTest extends ApiTestCase
|
|||
array $query,
|
||||
int $totalItems,
|
||||
int $expectedAmount,
|
||||
array $expectedVisits
|
||||
array $expectedVisits,
|
||||
): void {
|
||||
$resp = $this->callApiWithKey(self::METHOD_GET, '/visits/orphan', [RequestOptions::QUERY => $query]);
|
||||
$payload = $this->getJsonResponsePayload($resp);
|
||||
|
|
|
@ -51,7 +51,7 @@ class ResolveShortUrlTest extends ApiTestCase
|
|||
string $shortCode,
|
||||
?string $domain,
|
||||
string $expectedDetail,
|
||||
string $apiKey
|
||||
string $apiKey,
|
||||
): void {
|
||||
$resp = $this->callApiWithKey(self::METHOD_GET, $this->buildShortUrlPath($shortCode, $domain), [], $apiKey);
|
||||
$payload = $this->getJsonResponsePayload($resp);
|
||||
|
|
|
@ -23,7 +23,7 @@ class ShortUrlVisitsTest extends ApiTestCase
|
|||
string $shortCode,
|
||||
?string $domain,
|
||||
string $expectedDetail,
|
||||
string $apiKey
|
||||
string $apiKey,
|
||||
): void {
|
||||
$resp = $this->callApiWithKey(
|
||||
self::METHOD_GET,
|
||||
|
|
|
@ -19,7 +19,7 @@ class TagVisitsTest extends ApiTestCase
|
|||
string $apiKey,
|
||||
string $tag,
|
||||
bool $excludeBots,
|
||||
int $expectedVisitsAmount
|
||||
int $expectedVisitsAmount,
|
||||
): void {
|
||||
$resp = $this->callApiWithKey(self::METHOD_GET, sprintf('/tags/%s/visits', $tag), [
|
||||
RequestOptions::QUERY => $excludeBots ? ['excludeBots' => true] : [],
|
||||
|
|
|
@ -28,7 +28,7 @@ class CorsTest extends ApiTestCase
|
|||
public function responseIncludesCorsHeadersIfOriginIsSent(
|
||||
string $origin,
|
||||
string $endpoint,
|
||||
int $expectedStatusCode
|
||||
int $expectedStatusCode,
|
||||
): void {
|
||||
$resp = $this->callApiWithKey(self::METHOD_GET, $endpoint, [
|
||||
RequestOptions::HEADERS => ['Origin' => $origin],
|
||||
|
|
|
@ -49,7 +49,7 @@ class ListShortUrlsActionTest extends TestCase
|
|||
array $expectedTags,
|
||||
?string $expectedOrderBy,
|
||||
?string $startDate = null,
|
||||
?string $endDate = null
|
||||
?string $endDate = null,
|
||||
): void {
|
||||
$apiKey = ApiKey::create();
|
||||
$request = (new ServerRequest())->withQueryParams($query)->withAttribute(ApiKey::class, $apiKey);
|
||||
|
|
|
@ -88,7 +88,7 @@ class AuthenticationMiddlewareTest extends TestCase
|
|||
*/
|
||||
public function throwsExceptionWhenNoApiKeyIsProvided(
|
||||
ServerRequestInterface $request,
|
||||
string $expectedMessage
|
||||
string $expectedMessage,
|
||||
): void {
|
||||
$this->apiKeyService->check(Argument::any())->shouldNotBeCalled();
|
||||
$this->handler->handle($request)->shouldNotBeCalled();
|
||||
|
|
|
@ -91,7 +91,7 @@ class CrossDomainMiddlewareTest extends TestCase
|
|||
*/
|
||||
public function optionsRequestParsesRouteMatchToDetermineAllowedMethods(
|
||||
?string $allowHeader,
|
||||
string $expectedAllowedMethods
|
||||
string $expectedAllowedMethods,
|
||||
): void {
|
||||
$originalResponse = new Response();
|
||||
if ($allowHeader !== null) {
|
||||
|
@ -121,7 +121,7 @@ class CrossDomainMiddlewareTest extends TestCase
|
|||
public function expectedStatusCodeIsReturnDependingOnRequestMethod(
|
||||
string $method,
|
||||
int $status,
|
||||
int $expectedStatus
|
||||
int $expectedStatus,
|
||||
): void {
|
||||
$originalResponse = (new Response())->withStatus($status);
|
||||
$request = (new ServerRequest())->withMethod($method)
|
||||
|
|
Loading…
Add table
Reference in a new issue