Update to PHP coding standard 2.4.0

This commit is contained in:
Alejandro Celaya 2024-10-28 22:27:30 +01:00
parent 93a277a94d
commit 3f1d61e01e
192 changed files with 465 additions and 432 deletions

View File

@ -29,7 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
* *Nothing*
### Changed
* *Nothing*
* Update to Shlink PHP coding standard 2.4
### Deprecated
* *Nothing*

View File

@ -72,7 +72,7 @@
"phpunit/phpcov": "^10.0",
"phpunit/phpunit": "^11.4",
"roave/security-advisories": "dev-master",
"shlinkio/php-coding-standard": "~2.3.0",
"shlinkio/php-coding-standard": "~2.4.0",
"shlinkio/shlink-test-utils": "^4.1.1",
"symfony/var-dumper": "^7.1",
"veewee/composer-run-parallel": "^1.4"

View File

@ -26,7 +26,7 @@ class ReadEnvVarCommand extends Command
/** @var Closure(string $envVar): mixed */
private readonly Closure $loadEnvVar;
public function __construct(?Closure $loadEnvVar = null)
public function __construct(Closure|null $loadEnvVar = null)
{
$this->loadEnvVar = $loadEnvVar ?? static fn (string $envVar) => EnvVars::from($envVar)->loadFromEnv();
parent::__construct();

View File

@ -74,7 +74,7 @@ class DomainRedirectsCommand extends Command
$domainAuthority = $input->getArgument('domain');
$domain = $this->domainService->findByAuthority($domainAuthority);
$ask = static function (string $message, ?string $current) use ($io): ?string {
$ask = static function (string $message, string|null $current) use ($io): string|null {
if ($current === null) {
return $io->ask(sprintf('%s (Leave empty for no redirect)', $message));
}

View File

@ -22,7 +22,7 @@ class CreateShortUrlCommand extends Command
{
public const NAME = 'short-url:create';
private ?SymfonyStyle $io;
private SymfonyStyle|null $io;
private readonly ShortUrlDataInput $shortUrlDataInput;
public function __construct(

View File

@ -210,7 +210,7 @@ class ListShortUrlsCommand extends Command
return $shortUrls;
}
private function processOrderBy(InputInterface $input): ?string
private function processOrderBy(InputInterface $input): string|null
{
$orderBy = $input->getOption('order-by');
if (empty($orderBy)) {
@ -247,7 +247,7 @@ class ListShortUrlsCommand extends Command
$shortUrl->authorApiKey?->__toString() ?? '';
}
if ($input->getOption('show-api-key-name')) {
$columnsMap['API Key Name'] = static fn (array $_, ShortUrl $shortUrl): ?string =>
$columnsMap['API Key Name'] = static fn (array $_, ShortUrl $shortUrl): string|null =>
$shortUrl->authorApiKey?->name;
}

View File

@ -20,7 +20,7 @@ class DownloadGeoLiteDbCommand extends Command
{
public const NAME = 'visit:download-db';
private ?ProgressBar $progressBar = null;
private ProgressBar|null $progressBar = null;
public function __construct(private GeolocationDbUpdaterInterface $dbUpdater)
{

View File

@ -13,12 +13,12 @@ class GeolocationDbUpdateFailedException extends RuntimeException implements Exc
{
private bool $olderDbExists;
private function __construct(string $message, ?Throwable $previous = null)
private function __construct(string $message, Throwable|null $previous = null)
{
parent::__construct($message, previous: $previous);
}
public static function withOlderDb(?Throwable $prev = null): self
public static function withOlderDb(Throwable|null $prev = null): self
{
$e = new self(
'An error occurred while updating geolocation database, but an older DB is already present.',
@ -29,7 +29,7 @@ class GeolocationDbUpdateFailedException extends RuntimeException implements Exc
return $e;
}
public static function withoutOlderDb(?Throwable $prev = null): self
public static function withoutOlderDb(Throwable|null $prev = null): self
{
$e = new self(
'An error occurred while updating geolocation database, and an older version could not be found.',

View File

@ -40,8 +40,10 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
/**
* @throws GeolocationDbUpdateFailedException
*/
public function checkDbUpdate(?callable $beforeDownload = null, ?callable $handleProgress = null): GeolocationResult
{
public function checkDbUpdate(
callable|null $beforeDownload = null,
callable|null $handleProgress = null,
): GeolocationResult {
if ($this->trackingOptions->disableTracking || $this->trackingOptions->disableIpTracking) {
return GeolocationResult::CHECK_SKIPPED;
}
@ -59,7 +61,7 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
/**
* @throws GeolocationDbUpdateFailedException
*/
private function downloadIfNeeded(?callable $beforeDownload, ?callable $handleProgress): GeolocationResult
private function downloadIfNeeded(callable|null $beforeDownload, callable|null $handleProgress): GeolocationResult
{
if (! $this->dbUpdater->databaseFileExists()) {
return $this->downloadNewDb(false, $beforeDownload, $handleProgress);
@ -105,8 +107,8 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
*/
private function downloadNewDb(
bool $olderDbExists,
?callable $beforeDownload,
?callable $handleProgress,
callable|null $beforeDownload,
callable|null $handleProgress,
): GeolocationResult {
if ($beforeDownload !== null) {
$beforeDownload($olderDbExists);
@ -124,7 +126,7 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
}
}
private function wrapHandleProgressCallback(?callable $handleProgress, bool $olderDbExists): ?callable
private function wrapHandleProgressCallback(callable|null $handleProgress, bool $olderDbExists): callable|null
{
if ($handleProgress === null) {
return null;

View File

@ -12,7 +12,7 @@ interface GeolocationDbUpdaterInterface
* @throws GeolocationDbUpdateFailedException
*/
public function checkDbUpdate(
?callable $beforeDownload = null,
?callable $handleProgress = null,
callable|null $beforeDownload = null,
callable|null $handleProgress = null,
): GeolocationResult;
}

View File

@ -21,7 +21,7 @@ readonly class DateOption
$command->addOption($name, $shortcut, InputOption::VALUE_REQUIRED, $description);
}
public function get(InputInterface $input, OutputInterface $output): ?Chronos
public function get(InputInterface $input, OutputInterface $output): Chronos|null
{
$value = $input->getOption($this->name);
if (empty($value) || ! is_string($value)) {

View File

@ -23,7 +23,7 @@ readonly final class EndDateOption
));
}
public function get(InputInterface $input, OutputInterface $output): ?Chronos
public function get(InputInterface $input, OutputInterface $output): Chronos|null
{
return $this->dateOption->get($input, $output);
}

View File

@ -18,7 +18,7 @@ enum ShortUrlDataOption: string
case CRAWLABLE = 'crawlable';
case NO_FORWARD_QUERY = 'no-forward-query';
public function shortcut(): ?string
public function shortcut(): string|null
{
return match ($this) {
self::TAGS => 't',

View File

@ -19,7 +19,7 @@ readonly final class ShortUrlIdentifierInput
->addOption('domain', 'd', InputOption::VALUE_REQUIRED, $domainDesc);
}
public function shortCode(InputInterface $input): ?string
public function shortCode(InputInterface $input): string|null
{
return $input->getArgument('shortCode');
}

View File

@ -23,7 +23,7 @@ readonly final class StartDateOption
));
}
public function get(InputInterface $input, OutputInterface $output): ?Chronos
public function get(InputInterface $input, OutputInterface $output): Chronos|null
{
return $this->dateOption->get($input, $output);
}

View File

@ -33,7 +33,7 @@ use const STR_PAD_LEFT;
class RedirectRuleHandler implements RedirectRuleHandlerInterface
{
public function manageRules(StyleInterface $io, ShortUrl $shortUrl, array $rules): ?array
public function manageRules(StyleInterface $io, ShortUrl $shortUrl, array $rules): array|null
{
$amountOfRules = count($rules);
@ -213,7 +213,7 @@ class RedirectRuleHandler implements RedirectRuleHandlerInterface
private function askMandatory(string $message, StyleInterface $io): string
{
return $io->ask($message, validator: function (?string $answer): string {
return $io->ask($message, validator: function (string|null $answer): string {
if ($answer === null) {
throw new InvalidArgumentException('The value is mandatory');
}
@ -223,6 +223,6 @@ class RedirectRuleHandler implements RedirectRuleHandlerInterface
private function askOptional(string $message, StyleInterface $io): string
{
return $io->ask($message, validator: fn (?string $answer) => $answer === null ? '' : trim($answer));
return $io->ask($message, validator: fn (string|null $answer) => $answer === null ? '' : trim($answer));
}
}

View File

@ -16,5 +16,5 @@ interface RedirectRuleHandlerInterface
* @param ShortUrlRedirectRule[] $rules
* @return ShortUrlRedirectRule[]|null - A new list of rules to save, or null if no changes should be saved
*/
public function manageRules(StyleInterface $io, ShortUrl $shortUrl, array $rules): ?array;
public function manageRules(StyleInterface $io, ShortUrl $shortUrl, array $rules): array|null;
}

View File

@ -20,7 +20,7 @@ class ProcessRunner implements ProcessRunnerInterface
{
private Closure $createProcess;
public function __construct(private ProcessHelper $helper, ?callable $createProcess = null)
public function __construct(private ProcessHelper $helper, callable|null $createProcess = null)
{
$this->createProcess = $createProcess !== null
? $createProcess(...)

View File

@ -34,8 +34,12 @@ final class ShlinkTable
return new self($baseTable);
}
public function render(array $headers, array $rows, ?string $footerTitle = null, ?string $headerTitle = null): void
{
public function render(
array $headers,
array $rows,
string|null $footerTitle = null,
string|null $headerTitle = null,
): void {
$style = Table::getStyleDefinition(self::DEFAULT_STYLE_NAME);
$style->setFooterTitleFormat(self::TABLE_TITLE_STYLE)
->setHeaderTitleFormat(self::TABLE_TITLE_STYLE);

View File

@ -27,8 +27,11 @@ class InitialApiKeyCommandTest extends TestCase
}
#[Test, DataProvider('provideParams')]
public function initialKeyIsCreatedWithProvidedValue(?ApiKey $result, bool $verbose, string $expectedOutput): void
{
public function initialKeyIsCreatedWithProvidedValue(
ApiKey|null $result,
bool $verbose,
string $expectedOutput,
): void {
$this->apiKeyService->expects($this->once())->method('createInitial')->with('the_key')->willReturn($result);
$this->commandTester->execute(

View File

@ -31,7 +31,7 @@ class DomainRedirectsCommandTest extends TestCase
}
#[Test, DataProvider('provideDomains')]
public function onlyPlainQuestionsAreAskedForNewDomainsAndDomainsWithNoRedirects(?Domain $domain): void
public function onlyPlainQuestionsAreAskedForNewDomainsAndDomainsWithNoRedirects(Domain|null $domain): void
{
$domainAuthority = 'my-domain.com';
$this->domainService->expects($this->once())->method('findByAuthority')->with($domainAuthority)->willReturn(

View File

@ -104,7 +104,7 @@ class CreateShortUrlCommandTest extends TestCase
}
#[Test, DataProvider('provideDomains')]
public function properlyProcessesProvidedDomain(array $input, ?string $expectedDomain): void
public function properlyProcessesProvidedDomain(array $input, string|null $expectedDomain): void
{
$this->urlShortener->expects($this->once())->method('shorten')->with(
$this->callback(function (ShortUrlCreation $meta) use ($expectedDomain) {
@ -128,8 +128,10 @@ class CreateShortUrlCommandTest extends TestCase
}
#[Test, DataProvider('provideFlags')]
public function urlValidationHasExpectedValueBasedOnProvidedFlags(array $options, ?bool $expectedCrawlable): void
{
public function urlValidationHasExpectedValueBasedOnProvidedFlags(
array $options,
bool|null $expectedCrawlable,
): void {
$shortUrl = ShortUrl::createFake();
$this->urlShortener->expects($this->once())->method('shorten')->with(
$this->callback(function (ShortUrlCreation $meta) use ($expectedCrawlable) {

View File

@ -198,12 +198,12 @@ class ListShortUrlsCommandTest extends TestCase
#[Test, DataProvider('provideArgs')]
public function serviceIsInvokedWithProvidedArgs(
array $commandArgs,
?int $page,
?string $searchTerm,
int|null $page,
string|null $searchTerm,
array $tags,
string $tagsMode,
?string $startDate = null,
?string $endDate = null,
string|null $startDate = null,
string|null $endDate = null,
): void {
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([
'page' => $page,
@ -260,7 +260,7 @@ class ListShortUrlsCommandTest extends TestCase
}
#[Test, DataProvider('provideOrderBy')]
public function orderByIsProperlyComputed(array $commandArgs, ?string $expectedOrderBy): void
public function orderByIsProperlyComputed(array $commandArgs, string|null $expectedOrderBy): void
{
$this->shortUrlService->expects($this->once())->method('listShortUrls')->with(ShortUrlsParams::fromRawData([
'orderBy' => $expectedOrderBy,

View File

@ -15,7 +15,7 @@ use Throwable;
class GeolocationDbUpdateFailedExceptionTest extends TestCase
{
#[Test, DataProvider('providePrev')]
public function withOlderDbBuildsException(?Throwable $prev): void
public function withOlderDbBuildsException(Throwable|null $prev): void
{
$e = GeolocationDbUpdateFailedException::withOlderDb($prev);
@ -29,7 +29,7 @@ class GeolocationDbUpdateFailedExceptionTest extends TestCase
}
#[Test, DataProvider('providePrev')]
public function withoutOlderDbBuildsException(?Throwable $prev): void
public function withoutOlderDbBuildsException(Throwable|null $prev): void
{
$e = GeolocationDbUpdateFailedException::withoutOlderDb($prev);

View File

@ -180,7 +180,7 @@ class GeolocationDbUpdaterTest extends TestCase
yield 'both' => [new TrackingOptions(disableTracking: true, disableIpTracking: true)];
}
private function geolocationDbUpdater(?TrackingOptions $options = null): GeolocationDbUpdater
private function geolocationDbUpdater(TrackingOptions|null $options = null): GeolocationDbUpdater
{
$locker = $this->createMock(Lock\LockFactory::class);
$locker->method('createLock')->with($this->isType('string'))->willReturn($this->lock);

View File

@ -56,7 +56,7 @@ class RedirectRuleHandlerTest extends TestCase
#[Test, DataProvider('provideExitActions')]
public function commentIsDisplayedWhenRulesListIsEmpty(
RedirectRuleHandlerAction $action,
?array $expectedResult,
array|null $expectedResult,
): void {
$this->io->expects($this->once())->method('choice')->willReturn($action->value);
$this->io->expects($this->once())->method('newLine');

View File

@ -50,7 +50,7 @@ function generateRandomShortCode(int $length, ShortUrlMode $mode = ShortUrlMode:
return $nanoIdClient->formattedId($alphabet, $length);
}
function parseDateFromQuery(array $query, string $dateName): ?Chronos
function parseDateFromQuery(array $query, string $dateName): Chronos|null
{
return normalizeOptionalDate(empty($query[$dateName] ?? null) ? null : Chronos::parse($query[$dateName]));
}
@ -63,7 +63,7 @@ function parseDateRangeFromQuery(array $query, string $startDateName, string $en
return buildDateRange($startDate, $endDate);
}
function dateRangeToHumanFriendly(?DateRange $dateRange): string
function dateRangeToHumanFriendly(DateRange|null $dateRange): string
{
$startDate = $dateRange?->startDate;
$endDate = $dateRange?->endDate;
@ -83,7 +83,7 @@ function dateRangeToHumanFriendly(?DateRange $dateRange): string
/**
* @return ($date is null ? null : Chronos)
*/
function normalizeOptionalDate(string|DateTimeInterface|Chronos|null $date): ?Chronos
function normalizeOptionalDate(string|DateTimeInterface|Chronos|null $date): Chronos|null
{
$parsedDate = match (true) {
$date === null || $date instanceof Chronos => $date,
@ -148,7 +148,7 @@ function splitLocale(string $locale): array
/**
* @param InputFilter<mixed> $inputFilter
*/
function getOptionalIntFromInputFilter(InputFilter $inputFilter, string $fieldName): ?int
function getOptionalIntFromInputFilter(InputFilter $inputFilter, string $fieldName): int|null
{
$value = $inputFilter->getValue($fieldName);
return $value !== null ? (int) $value : null;
@ -157,7 +157,7 @@ function getOptionalIntFromInputFilter(InputFilter $inputFilter, string $fieldNa
/**
* @param InputFilter<mixed> $inputFilter
*/
function getOptionalBoolFromInputFilter(InputFilter $inputFilter, string $fieldName): ?bool
function getOptionalBoolFromInputFilter(InputFilter $inputFilter, string $fieldName): bool|null
{
$value = $inputFilter->getValue($fieldName);
return $value !== null ? (bool) $value : null;
@ -276,7 +276,7 @@ function enumToString(string $enum): string
* Split provided string by comma and return a list of the results.
* An empty array is returned if provided value is empty
*/
function splitByComma(?string $value): array
function splitByComma(string|null $value): array
{
if ($value === null || trim($value) === '') {
return [];
@ -285,7 +285,7 @@ function splitByComma(?string $value): array
return array_map(trim(...), explode(',', $value));
}
function ipAddressFromRequest(ServerRequestInterface $request): ?string
function ipAddressFromRequest(ServerRequestInterface $request): string|null
{
return $request->getAttribute(IpAddressMiddlewareFactory::REQUEST_ATTR);
}

View File

@ -123,7 +123,7 @@ final class QrCodeParams
return self::parseHexColor($bgColor, DEFAULT_QR_CODE_BG_COLOR);
}
private static function parseHexColor(string $hexColor, ?string $fallback): Color
private static function parseHexColor(string $hexColor, string|null $fallback): Color
{
$hexColor = ltrim($hexColor, '#');
if (! ctype_xdigit($hexColor) && $fallback !== null) {

View File

@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\Core\Config;
final class EmptyNotFoundRedirectConfig implements NotFoundRedirectConfigInterface
{
public function invalidShortUrlRedirect(): ?string
public function invalidShortUrlRedirect(): string|null
{
return null;
}
@ -16,7 +16,7 @@ final class EmptyNotFoundRedirectConfig implements NotFoundRedirectConfigInterfa
return false;
}
public function regular404Redirect(): ?string
public function regular404Redirect(): string|null
{
return null;
}
@ -26,7 +26,7 @@ final class EmptyNotFoundRedirectConfig implements NotFoundRedirectConfigInterfa
return false;
}
public function baseUrlRedirect(): ?string
public function baseUrlRedirect(): string|null
{
return null;
}

View File

@ -6,15 +6,15 @@ namespace Shlinkio\Shlink\Core\Config;
interface NotFoundRedirectConfigInterface
{
public function invalidShortUrlRedirect(): ?string;
public function invalidShortUrlRedirect(): string|null;
public function hasInvalidShortUrlRedirect(): bool;
public function regular404Redirect(): ?string;
public function regular404Redirect(): string|null;
public function hasRegular404Redirect(): bool;
public function baseUrlRedirect(): ?string;
public function baseUrlRedirect(): string|null;
public function hasBaseUrlRedirect(): bool;
}

View File

@ -30,7 +30,7 @@ class NotFoundRedirectResolver implements NotFoundRedirectResolverInterface
NotFoundType $notFoundType,
NotFoundRedirectConfigInterface $config,
UriInterface $currentUri,
): ?ResponseInterface {
): ResponseInterface|null {
$urlToRedirectTo = match (true) {
$notFoundType->isBaseUrl() && $config->hasBaseUrlRedirect() => $config->baseUrlRedirect(),
$notFoundType->isRegularNotFound() && $config->hasRegular404Redirect() => $config->regular404Redirect(),

View File

@ -14,5 +14,5 @@ interface NotFoundRedirectResolverInterface
NotFoundType $notFoundType,
NotFoundRedirectConfigInterface $config,
UriInterface $currentUri,
): ?ResponseInterface;
): ResponseInterface|null;
}

View File

@ -9,16 +9,16 @@ use JsonSerializable;
final class NotFoundRedirects implements JsonSerializable
{
private function __construct(
public readonly ?string $baseUrlRedirect,
public readonly ?string $regular404Redirect,
public readonly ?string $invalidShortUrlRedirect,
public readonly string|null $baseUrlRedirect,
public readonly string|null $regular404Redirect,
public readonly string|null $invalidShortUrlRedirect,
) {
}
public static function withRedirects(
?string $baseUrlRedirect,
?string $regular404Redirect = null,
?string $invalidShortUrlRedirect = null,
string|null $baseUrlRedirect,
string|null $regular404Redirect = null,
string|null $invalidShortUrlRedirect = null,
): self {
return new self($baseUrlRedirect, $regular404Redirect, $invalidShortUrlRedirect);
}

View File

@ -10,9 +10,9 @@ use Shlinkio\Shlink\Core\Config\NotFoundRedirectConfigInterface;
final readonly class NotFoundRedirectOptions implements NotFoundRedirectConfigInterface
{
public function __construct(
public ?string $invalidShortUrl = null,
public ?string $regular404 = null,
public ?string $baseUrl = null,
public string|null $invalidShortUrl = null,
public string|null $regular404 = null,
public string|null $baseUrl = null,
) {
}
@ -25,7 +25,7 @@ final readonly class NotFoundRedirectOptions implements NotFoundRedirectConfigIn
);
}
public function invalidShortUrlRedirect(): ?string
public function invalidShortUrlRedirect(): string|null
{
return $this->invalidShortUrl;
}
@ -35,7 +35,7 @@ final readonly class NotFoundRedirectOptions implements NotFoundRedirectConfigIn
return $this->invalidShortUrl !== null;
}
public function regular404Redirect(): ?string
public function regular404Redirect(): string|null
{
return $this->regular404;
}
@ -45,7 +45,7 @@ final readonly class NotFoundRedirectOptions implements NotFoundRedirectConfigIn
return $this->regular404 !== null;
}
public function baseUrlRedirect(): ?string
public function baseUrlRedirect(): string|null
{
return $this->baseUrl;
}

View File

@ -26,7 +26,7 @@ final readonly class QrCodeOptions
public bool $enabledForDisabledShortUrls = DEFAULT_QR_CODE_ENABLED_FOR_DISABLED_SHORT_URLS,
public string $color = DEFAULT_QR_CODE_COLOR,
public string $bgColor = DEFAULT_QR_CODE_BG_COLOR,
public ?string $logoUrl = null,
public string|null $logoUrl = null,
) {
}

View File

@ -22,7 +22,7 @@ final readonly class TrackingOptions
public bool $trackOrphanVisits = true,
// A query param that, if provided, will disable tracking of one particular visit. Always takes precedence over
// other options
public ?string $disableTrackParam = null,
public string|null $disableTrackParam = null,
// If true, visits will not be tracked at all
public bool $disableTracking = false,
// If true, visits will be tracked, but neither the IP address, nor the location will be resolved

View File

@ -26,7 +26,7 @@ readonly class DomainService implements DomainServiceInterface
/**
* @return DomainItem[]
*/
public function listDomains(?ApiKey $apiKey = null): array
public function listDomains(ApiKey|null $apiKey = null): array
{
[$default, $domains] = $this->defaultDomainAndRest($apiKey);
$mappedDomains = array_map(fn (Domain $domain) => DomainItem::forNonDefaultDomain($domain), $domains);
@ -47,7 +47,7 @@ readonly class DomainService implements DomainServiceInterface
/**
* @return array{Domain|null, Domain[]}
*/
private function defaultDomainAndRest(?ApiKey $apiKey): array
private function defaultDomainAndRest(ApiKey|null $apiKey): array
{
/** @var DomainRepositoryInterface $repo */
$repo = $this->em->getRepository(Domain::class);
@ -80,7 +80,7 @@ readonly class DomainService implements DomainServiceInterface
return $domain;
}
public function findByAuthority(string $authority, ?ApiKey $apiKey = null): ?Domain
public function findByAuthority(string $authority, ApiKey|null $apiKey = null): Domain|null
{
return $this->em->getRepository(Domain::class)->findOneByAuthority($authority, $apiKey);
}
@ -88,7 +88,7 @@ readonly class DomainService implements DomainServiceInterface
/**
* @throws DomainNotFoundException
*/
public function getOrCreate(string $authority, ?ApiKey $apiKey = null): Domain
public function getOrCreate(string $authority, ApiKey|null $apiKey = null): Domain
{
$domain = $this->getPersistedDomain($authority, $apiKey);
$this->em->flush();
@ -102,7 +102,7 @@ readonly class DomainService implements DomainServiceInterface
public function configureNotFoundRedirects(
string $authority,
NotFoundRedirects $notFoundRedirects,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): Domain {
$domain = $this->getPersistedDomain($authority, $apiKey);
$domain->configureNotFoundRedirects($notFoundRedirects);
@ -115,7 +115,7 @@ readonly class DomainService implements DomainServiceInterface
/**
* @throws DomainNotFoundException
*/
private function getPersistedDomain(string $authority, ?ApiKey $apiKey): Domain
private function getPersistedDomain(string $authority, ApiKey|null $apiKey): Domain
{
$domain = $this->findByAuthority($authority, $apiKey);
if ($domain === null && $apiKey?->hasRole(Role::DOMAIN_SPECIFIC)) {

View File

@ -15,7 +15,7 @@ interface DomainServiceInterface
/**
* @return DomainItem[]
*/
public function listDomains(?ApiKey $apiKey = null): array;
public function listDomains(ApiKey|null $apiKey = null): array;
/**
* @throws DomainNotFoundException
@ -25,9 +25,9 @@ interface DomainServiceInterface
/**
* @throws DomainNotFoundException If the API key is restricted to one domain and a different one is provided
*/
public function getOrCreate(string $authority, ?ApiKey $apiKey = null): Domain;
public function getOrCreate(string $authority, ApiKey|null $apiKey = null): Domain;
public function findByAuthority(string $authority, ?ApiKey $apiKey = null): ?Domain;
public function findByAuthority(string $authority, ApiKey|null $apiKey = null): Domain|null;
/**
* @throws DomainNotFoundException If the API key is restricted to one domain and a different one is provided
@ -35,6 +35,6 @@ interface DomainServiceInterface
public function configureNotFoundRedirects(
string $authority,
NotFoundRedirects $notFoundRedirects,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): Domain;
}

View File

@ -15,9 +15,9 @@ class Domain extends AbstractEntity implements JsonSerializable, NotFoundRedirec
private function __construct(
public readonly string $authority,
private ?string $baseUrlRedirect = null,
private ?string $regular404Redirect = null,
private ?string $invalidShortUrlRedirect = null,
private string|null $baseUrlRedirect = null,
private string|null $regular404Redirect = null,
private string|null $invalidShortUrlRedirect = null,
) {
}
@ -31,7 +31,7 @@ class Domain extends AbstractEntity implements JsonSerializable, NotFoundRedirec
return $this->authority;
}
public function invalidShortUrlRedirect(): ?string
public function invalidShortUrlRedirect(): string|null
{
return $this->invalidShortUrlRedirect;
}
@ -41,7 +41,7 @@ class Domain extends AbstractEntity implements JsonSerializable, NotFoundRedirec
return $this->invalidShortUrlRedirect !== null;
}
public function regular404Redirect(): ?string
public function regular404Redirect(): string|null
{
return $this->regular404Redirect;
}
@ -51,7 +51,7 @@ class Domain extends AbstractEntity implements JsonSerializable, NotFoundRedirec
return $this->regular404Redirect !== null;
}
public function baseUrlRedirect(): ?string
public function baseUrlRedirect(): string|null
{
return $this->baseUrlRedirect;
}

View File

@ -20,7 +20,7 @@ class DomainRepository extends EntitySpecificationRepository implements DomainRe
/**
* @return Domain[]
*/
public function findDomains(?ApiKey $apiKey = null): array
public function findDomains(ApiKey|null $apiKey = null): array
{
$qb = $this->createQueryBuilder('d');
$qb->leftJoin(ShortUrl::class, 's', Join::WITH, 's.domain = d')
@ -39,7 +39,7 @@ class DomainRepository extends EntitySpecificationRepository implements DomainRe
return $qb->getQuery()->getResult();
}
public function findOneByAuthority(string $authority, ?ApiKey $apiKey = null): ?Domain
public function findOneByAuthority(string $authority, ApiKey|null $apiKey = null): Domain|null
{
$qb = $this->createDomainQueryBuilder($authority, $apiKey);
$qb->select('d');
@ -47,7 +47,7 @@ class DomainRepository extends EntitySpecificationRepository implements DomainRe
return $qb->getQuery()->getOneOrNullResult();
}
public function domainExists(string $authority, ?ApiKey $apiKey = null): bool
public function domainExists(string $authority, ApiKey|null $apiKey = null): bool
{
$qb = $this->createDomainQueryBuilder($authority, $apiKey);
$qb->select('COUNT(d.id)');
@ -55,7 +55,7 @@ class DomainRepository extends EntitySpecificationRepository implements DomainRe
return ((int) $qb->getQuery()->getSingleScalarResult()) > 0;
}
private function createDomainQueryBuilder(string $authority, ?ApiKey $apiKey): QueryBuilder
private function createDomainQueryBuilder(string $authority, ApiKey|null $apiKey): QueryBuilder
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->from(Domain::class, 'd')
@ -72,7 +72,7 @@ class DomainRepository extends EntitySpecificationRepository implements DomainRe
return $qb;
}
private function determineExtraSpecs(?ApiKey $apiKey): iterable
private function determineExtraSpecs(ApiKey|null $apiKey): iterable
{
// FIXME The $apiKey->spec() method cannot be used here, as it returns a single spec which assumes the
// ShortUrl is the root entity. Here, the Domain is the root entity.

View File

@ -15,9 +15,9 @@ interface DomainRepositoryInterface extends ObjectRepository, EntitySpecificatio
/**
* @return Domain[]
*/
public function findDomains(?ApiKey $apiKey = null): array;
public function findDomains(ApiKey|null $apiKey = null): array;
public function findOneByAuthority(string $authority, ?ApiKey $apiKey = null): ?Domain;
public function findOneByAuthority(string $authority, ApiKey|null $apiKey = null): Domain|null;
public function domainExists(string $authority, ?ApiKey $apiKey = null): bool;
public function domainExists(string $authority, ApiKey|null $apiKey = null): bool;
}

View File

@ -10,7 +10,7 @@ use Happyr\DoctrineSpecification\Specification\BaseSpecification;
class IsDomain extends BaseSpecification
{
public function __construct(private string $domainId, ?string $context = null)
public function __construct(private string $domainId, string|null $context = null)
{
parent::__construct($context);
}

View File

@ -13,7 +13,7 @@ use function rtrim;
class NotFoundType
{
private function __construct(private readonly ?VisitType $type)
private function __construct(private readonly VisitType|null $type)
{
}

View File

@ -40,7 +40,7 @@ readonly class NotFoundRedirectHandler implements MiddlewareInterface
private function resolveDomainSpecificRedirect(
UriInterface $currentUri,
NotFoundType $notFoundType,
): ?ResponseInterface {
): ResponseInterface|null {
$domain = $this->domainService->findByAuthority($currentUri->getAuthority());
if ($domain === null) {
return null;

View File

@ -23,7 +23,7 @@ class NotFoundTemplateHandler implements RequestHandlerInterface
private Closure $readFile;
public function __construct(?callable $readFile = null)
public function __construct(callable|null $readFile = null)
{
$this->readFile = $readFile ? Closure::fromCallable($readFile) : fn (string $file) => file_get_contents($file);
}

View File

@ -11,7 +11,7 @@ abstract class AbstractVisitEvent implements JsonSerializable, JsonUnserializabl
{
final public function __construct(
public readonly string $visitId,
public readonly ?string $originalIpAddress = null,
public readonly string|null $originalIpAddress = null,
) {
}

View File

@ -45,7 +45,7 @@ readonly class LocateVisit
$this->eventDispatcher->dispatch(new VisitLocated($visitId, $shortUrlVisited->originalIpAddress));
}
private function locateVisit(string $visitId, ?string $originalIpAddress, Visit $visit): void
private function locateVisit(string $visitId, string|null $originalIpAddress, Visit $visit): void
{
if (! $this->dbUpdater->databaseFileExists()) {
$this->logger->warning('Tried to locate visit with id "{visitId}", but a GeoLite2 db was not found.', [

View File

@ -48,7 +48,7 @@ final readonly class PublishingUpdatesGenerator implements PublishingUpdatesGene
]);
}
private function transformShortUrl(?ShortUrl $shortUrl): array
private function transformShortUrl(ShortUrl|null $shortUrl): array
{
return $shortUrl === null ? [] : $this->shortUrlTransformer->transform($shortUrl);
}

View File

@ -12,7 +12,7 @@ enum Topic: string
case NEW_ORPHAN_VISIT = 'https://shlink.io/new-orphan-visit';
case NEW_SHORT_URL = 'https://shlink.io/new-short-url';
public static function newShortUrlVisit(?string $shortCode): string
public static function newShortUrlVisit(string|null $shortCode): string
{
return sprintf('%s/%s', self::NEW_VISIT->value, $shortCode ?? '');
}

View File

@ -13,7 +13,7 @@ class IpCannotBeLocatedException extends RuntimeException
string $message,
public readonly UnlocatableIpType $type,
int $code = 0,
?Throwable $previous = null,
Throwable|null $previous = null,
) {
parent::__construct($message, $code, $previous);
}

View File

@ -19,7 +19,7 @@ class NonUniqueSlugException extends InvalidArgumentException implements Problem
private const TITLE = 'Invalid custom slug';
public const ERROR_CODE = 'non-unique-slug';
public static function fromSlug(string $slug, ?string $domain = null): self
public static function fromSlug(string $slug, string|null $domain = null): self
{
$suffix = $domain === null ? '' : sprintf(' for domain "%s"', $domain);
$e = new self(sprintf('Provided slug "%s" is already in use%s.', $slug, $suffix));

View File

@ -29,12 +29,12 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
/**
* @param InputFilterInterface<mixed> $inputFilter
*/
public static function fromInputFilter(InputFilterInterface $inputFilter, ?Throwable $prev = null): self
public static function fromInputFilter(InputFilterInterface $inputFilter, Throwable|null $prev = null): self
{
return static::fromArray($inputFilter->getMessages(), $prev);
}
public static function fromArray(array $invalidData, ?Throwable $prev = null): self
public static function fromArray(array $invalidData, Throwable|null $prev = null): self
{
$status = StatusCodeInterface::STATUS_BAD_REQUEST;
$e = new self('Provided data is not valid', $status, $prev);

View File

@ -13,9 +13,9 @@ final readonly class MatomoOptions
*/
public function __construct(
public bool $enabled = false,
public ?string $baseUrl = null,
public string|null $baseUrl = null,
private string|int|null $siteId = null,
public ?string $apiToken = null,
public string|null $apiToken = null,
) {
}
@ -29,7 +29,7 @@ final readonly class MatomoOptions
);
}
public function siteId(): ?int
public function siteId(): int|null
{
if ($this->siteId === null) {
return null;

View File

@ -45,7 +45,7 @@ readonly class MatomoVisitSender implements MatomoVisitSenderInterface
return new SendVisitsResult($successfulVisits, $failedVisits);
}
public function sendVisit(Visit $visit, ?string $originalIpAddress = null): void
public function sendVisit(Visit $visit, string|null $originalIpAddress = null): void
{
$tracker = $this->trackerBuilder->buildMatomoTracker();

View File

@ -18,5 +18,5 @@ interface MatomoVisitSenderInterface
VisitSendingProgressTrackerInterface|null $progressTracker = null,
): SendVisitsResult;
public function sendVisit(Visit $visit, ?string $originalIpAddress = null): void;
public function sendVisit(Visit $visit, string|null $originalIpAddress = null): void;
}

View File

@ -13,18 +13,18 @@ abstract class AbstractInfinitePaginableListParams
public readonly int $page;
public readonly int $itemsPerPage;
protected function __construct(?int $page, ?int $itemsPerPage)
protected function __construct(int|null $page, int|null $itemsPerPage)
{
$this->page = $this->determinePage($page);
$this->itemsPerPage = $this->determineItemsPerPage($itemsPerPage);
}
private function determinePage(?int $page): int
private function determinePage(int|null $page): int
{
return $page === null || $page <= 0 ? self::FIRST_PAGE : $page;
}
private function determineItemsPerPage(?int $itemsPerPage): int
private function determineItemsPerPage(int|null $itemsPerPage): int
{
return $itemsPerPage === null || $itemsPerPage < 0 ? Paginator::ALL_ITEMS : $itemsPerPage;
}

View File

@ -10,7 +10,7 @@ enum DeviceType: string
case IOS = 'ios';
case DESKTOP = 'desktop';
public static function matchFromUserAgent(string $userAgent): ?self
public static function matchFromUserAgent(string $userAgent): self|null
{
$detect = new MobileDetect();
$detect->setUserAgent($userAgent);

View File

@ -10,7 +10,7 @@ final readonly class Ordering
private const ASC_DIR = 'ASC';
private const DEFAULT_DIR = self::ASC_DIR;
public function __construct(public ?string $field = null, public string $direction = self::DEFAULT_DIR)
public function __construct(public string|null $field = null, public string $direction = self::DEFAULT_DIR)
{
}

View File

@ -12,7 +12,7 @@ use Pagerfanta\Adapter\AdapterInterface;
*/
abstract class AbstractCacheableCountPaginatorAdapter implements AdapterInterface
{
private ?int $count = null;
private int|null $count = null;
final public function getNbResults(): int
{

View File

@ -24,7 +24,7 @@ class RedirectCondition extends AbstractEntity implements JsonSerializable
private function __construct(
private readonly RedirectConditionType $type,
private readonly string $matchValue,
private readonly ?string $matchKey = null,
private readonly string|null $matchKey = null,
) {
}

View File

@ -30,7 +30,7 @@ readonly class DeleteShortUrlService implements DeleteShortUrlServiceInterface
public function deleteByShortCode(
ShortUrlIdentifier $identifier,
bool $ignoreThreshold = false,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): void {
$shortUrl = $this->urlResolver->resolveShortUrl($identifier, $apiKey);
if (! $ignoreThreshold && $this->isThresholdReached($shortUrl)) {

View File

@ -18,7 +18,7 @@ interface DeleteShortUrlServiceInterface
public function deleteByShortCode(
ShortUrlIdentifier $identifier,
bool $ignoreThreshold = false,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): void;
/**

View File

@ -49,19 +49,19 @@ class ShortUrl extends AbstractEntity
private Collection $tags = new ArrayCollection(),
private Collection & Selectable $visits = new ArrayCollection(),
private Collection & Selectable $visitsCounts = new ArrayCollection(),
private ?Chronos $validSince = null,
private ?Chronos $validUntil = null,
private ?int $maxVisits = null,
private ?Domain $domain = null,
private Chronos|null $validSince = null,
private Chronos|null $validUntil = null,
private int|null $maxVisits = null,
private Domain|null $domain = null,
private bool $customSlugWasProvided = false,
private int $shortCodeLength = 0,
public readonly ?ApiKey $authorApiKey = null,
private ?string $title = null,
public readonly ApiKey|null $authorApiKey = null,
private string|null $title = null,
private bool $titleWasAutoResolved = false,
private bool $crawlable = false,
private bool $forwardQuery = true,
private ?string $importSource = null,
private ?string $importOriginalShortCode = null,
private string|null $importSource = null,
private string|null $importOriginalShortCode = null,
private Collection $redirectRules = new ArrayCollection(),
) {
}
@ -85,7 +85,7 @@ class ShortUrl extends AbstractEntity
public static function create(
ShortUrlCreation $creation,
?ShortUrlRelationResolverInterface $relationResolver = null,
ShortUrlRelationResolverInterface|null $relationResolver = null,
): self {
$relationResolver = $relationResolver ?? new SimpleShortUrlRelationResolver();
$shortCodeLength = $creation->shortCodeLength;
@ -115,7 +115,7 @@ class ShortUrl extends AbstractEntity
public static function fromImport(
ImportedShlinkUrl $url,
bool $importShortCode,
?ShortUrlRelationResolverInterface $relationResolver = null,
ShortUrlRelationResolverInterface|null $relationResolver = null,
): self {
$meta = [
ShortUrlInputFilter::LONG_URL => $url->longUrl,
@ -141,7 +141,7 @@ class ShortUrl extends AbstractEntity
public function update(
ShortUrlEdition $shortUrlEdit,
?ShortUrlRelationResolverInterface $relationResolver = null,
ShortUrlRelationResolverInterface|null $relationResolver = null,
): void {
if ($shortUrlEdit->validSinceWasProvided()) {
$this->validSince = $shortUrlEdit->validSince;
@ -185,7 +185,7 @@ class ShortUrl extends AbstractEntity
return $this->shortCode;
}
public function getDomain(): ?Domain
public function getDomain(): Domain|null
{
return $this->domain;
}
@ -195,7 +195,7 @@ class ShortUrl extends AbstractEntity
return $this->forwardQuery;
}
public function title(): ?string
public function title(): string|null
{
return $this->title;
}
@ -205,7 +205,7 @@ class ShortUrl extends AbstractEntity
return count($this->visits) >= $visitsAmount;
}
public function mostRecentImportedVisitDate(): ?Chronos
public function mostRecentImportedVisitDate(): Chronos|null
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('type', VisitType::IMPORTED))
->orderBy(['id' => 'DESC'])
@ -270,7 +270,7 @@ class ShortUrl extends AbstractEntity
* Providing the raw authority as `string|null` would result in a fallback to `$this->domain` when the authority
* was null.
*/
public function toArray(?VisitsSummary $precalculatedSummary = null, callable|null $getAuthority = null): array
public function toArray(VisitsSummary|null $precalculatedSummary = null, callable|null $getAuthority = null): array
{
return [
'shortCode' => $this->shortCode,

View File

@ -25,7 +25,7 @@ readonly class ShortUrlRedirectionBuilder implements ShortUrlRedirectionBuilderI
public function buildShortUrlRedirect(
ShortUrl $shortUrl,
ServerRequestInterface $request,
?string $extraPath = null,
string|null $extraPath = null,
): string {
$uri = new Uri($this->redirectionResolver->resolveLongUrl($shortUrl, $request));
$shouldForwardQuery = $shortUrl->forwardQuery();
@ -58,7 +58,7 @@ readonly class ShortUrlRedirectionBuilder implements ShortUrlRedirectionBuilderI
return Query::build($mergedQuery);
}
private function resolvePath(string $basePath, ?string $extraPath): string
private function resolvePath(string $basePath, string|null $extraPath): string
{
return $extraPath === null ? $basePath : sprintf('%s%s', $basePath, $extraPath);
}

View File

@ -12,6 +12,6 @@ interface ShortUrlRedirectionBuilderInterface
public function buildShortUrlRedirect(
ShortUrl $shortUrl,
ServerRequestInterface $request,
?string $extraPath = null,
string|null $extraPath = null,
): string;
}

View File

@ -61,7 +61,7 @@ readonly class ShortUrlTitleResolutionHelper implements ShortUrlTitleResolutionH
return $title !== null ? $data->withResolvedTitle($title) : $data;
}
private function fetchUrl(string $url): ?ResponseInterface
private function fetchUrl(string $url): ResponseInterface|null
{
try {
return $this->httpClient->request(RequestMethodInterface::METHOD_GET, $url, [
@ -80,7 +80,7 @@ readonly class ShortUrlTitleResolutionHelper implements ShortUrlTitleResolutionH
}
}
private function tryToResolveTitle(ResponseInterface $response, string $contentType): ?string
private function tryToResolveTitle(ResponseInterface $response, string $contentType): string|null
{
$collectedBody = '';
$body = $response->getBody();

View File

@ -47,7 +47,7 @@ class ExtraPathRedirectMiddleware implements MiddlewareInterface
return $this->tryToResolveRedirect($request, $handler);
}
private function shouldApplyLogic(?NotFoundType $notFoundType): bool
private function shouldApplyLogic(NotFoundType|null $notFoundType): bool
{
if ($notFoundType === null || ! $this->urlShortenerOptions->appendExtraPath) {
return false;

View File

@ -26,17 +26,17 @@ final readonly class ShortUrlCreation implements TitleResolutionModelInterface
private function __construct(
public string $longUrl,
public ShortUrlMode $shortUrlMode,
public ?Chronos $validSince = null,
public ?Chronos $validUntil = null,
public ?string $customSlug = null,
public ?string $pathPrefix = null,
public ?int $maxVisits = null,
public Chronos|null $validSince = null,
public Chronos|null $validUntil = null,
public string|null $customSlug = null,
public string|null $pathPrefix = null,
public int|null $maxVisits = null,
public bool $findIfExists = false,
public ?string $domain = null,
public string|null $domain = null,
public int $shortCodeLength = 5,
public ?ApiKey $apiKey = null,
public ApiKey|null $apiKey = null,
public array $tags = [],
public ?string $title = null,
public string|null $title = null,
public bool $titleWasAutoResolved = false,
public bool $crawlable = false,
public bool $forwardQuery = true,

View File

@ -21,17 +21,17 @@ final readonly class ShortUrlEdition implements TitleResolutionModelInterface
*/
private function __construct(
private bool $longUrlPropWasProvided = false,
public ?string $longUrl = null,
public string|null $longUrl = null,
private bool $validSincePropWasProvided = false,
public ?Chronos $validSince = null,
public Chronos|null $validSince = null,
private bool $validUntilPropWasProvided = false,
public ?Chronos $validUntil = null,
public Chronos|null $validUntil = null,
private bool $maxVisitsPropWasProvided = false,
public ?int $maxVisits = null,
public int|null $maxVisits = null,
private bool $tagsPropWasProvided = false,
public array $tags = [],
private bool $titlePropWasProvided = false,
public ?string $title = null,
public string|null $title = null,
public bool $titleWasAutoResolved = false,
private bool $crawlablePropWasProvided = false,
public bool $crawlable = false,

View File

@ -11,7 +11,7 @@ use function sprintf;
final readonly class ShortUrlIdentifier
{
private function __construct(public string $shortCode, public ?string $domain = null)
private function __construct(public string $shortCode, public string|null $domain = null)
{
}
@ -39,7 +39,7 @@ final readonly class ShortUrlIdentifier
return new self($shortUrl->getShortCode(), $domainAuthority);
}
public static function fromShortCodeAndDomain(string $shortCode, ?string $domain = null): self
public static function fromShortCodeAndDomain(string $shortCode, string|null $domain = null): self
{
return new self($shortCode, $domain);
}

View File

@ -22,7 +22,7 @@ final class ShortUrlsParams
public readonly string|null $searchTerm,
public readonly array $tags,
public readonly Ordering $orderBy,
public readonly ?DateRange $dateRange,
public readonly DateRange|null $dateRange,
public readonly bool $excludeMaxVisitsReached,
public readonly bool $excludePastValidUntil,
public readonly TagsMode $tagsMode = TagsMode::ANY,
@ -64,7 +64,7 @@ final class ShortUrlsParams
);
}
private static function resolveTagsMode(?string $rawTagsMode): TagsMode
private static function resolveTagsMode(string|null $rawTagsMode): TagsMode
{
if ($rawTagsMode === null) {
return TagsMode::ANY;

View File

@ -11,7 +11,7 @@ final class UrlShorteningResult
{
private function __construct(
public readonly ShortUrl $shortUrl,
private readonly ?Throwable $errorOnEventDispatching,
private readonly Throwable|null $errorOnEventDispatching,
) {
}

View File

@ -109,7 +109,7 @@ class ShortUrlInputFilter extends InputFilter
$title = InputFactory::basic(self::TITLE);
$title->getFilterChain()->attach(new Filter\Callback(
static fn (?string $value) => $value === null ? $value : substr($value, 0, 512),
static fn (string|null $value) => $value === null ? $value : substr($value, 0, 512),
));
$this->add($title);

View File

@ -18,7 +18,7 @@ readonly class ShortUrlRepositoryAdapter implements AdapterInterface
public function __construct(
private ShortUrlListRepositoryInterface $repository,
private ShortUrlsParams $params,
private ?ApiKey $apiKey,
private ApiKey|null $apiKey,
private string $defaultDomain,
) {
}

View File

@ -17,15 +17,15 @@ class ShortUrlsCountFiltering
public readonly bool $searchIncludesDefaultDomain;
public function __construct(
public readonly ?string $searchTerm = null,
public readonly string|null $searchTerm = null,
public readonly array $tags = [],
public readonly ?TagsMode $tagsMode = null,
public readonly ?DateRange $dateRange = null,
public readonly TagsMode|null $tagsMode = null,
public readonly DateRange|null $dateRange = null,
public readonly bool $excludeMaxVisitsReached = false,
public readonly bool $excludePastValidUntil = false,
public readonly ?ApiKey $apiKey = null,
?string $defaultDomain = null,
public readonly ?string $domain = null,
public readonly ApiKey|null $apiKey = null,
string|null $defaultDomain = null,
public readonly string|null $domain = null,
) {
$this->searchIncludesDefaultDomain = !empty($searchTerm) && !empty($defaultDomain) && str_contains(
strtolower($defaultDomain),
@ -33,7 +33,7 @@ class ShortUrlsCountFiltering
);
}
public static function fromParams(ShortUrlsParams $params, ?ApiKey $apiKey, string $defaultDomain): self
public static function fromParams(ShortUrlsParams $params, ApiKey|null $apiKey, string $defaultDomain): self
{
return new self(
$params->searchTerm,

View File

@ -13,19 +13,19 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlsListFiltering extends ShortUrlsCountFiltering
{
public function __construct(
public readonly ?int $limit = null,
public readonly ?int $offset = null,
public readonly int|null $limit = null,
public readonly int|null $offset = null,
public readonly Ordering $orderBy = new Ordering(),
?string $searchTerm = null,
string|null $searchTerm = null,
array $tags = [],
?TagsMode $tagsMode = null,
?DateRange $dateRange = null,
TagsMode|null $tagsMode = null,
DateRange|null $dateRange = null,
bool $excludeMaxVisitsReached = false,
bool $excludePastValidUntil = false,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
// Used only to determine if search term includes default domain
?string $defaultDomain = null,
?string $domain = null,
string|null $defaultDomain = null,
string|null $domain = null,
) {
parent::__construct(
$searchTerm,
@ -44,7 +44,7 @@ class ShortUrlsListFiltering extends ShortUrlsCountFiltering
int $limit,
int $offset,
ShortUrlsParams $params,
?ApiKey $apiKey,
ApiKey|null $apiKey,
string $defaultDomain,
): self {
return new self(

View File

@ -23,7 +23,7 @@ use function strtolower;
/** @extends EntitySpecificationRepository<ShortUrl> */
class ShortUrlRepository extends EntitySpecificationRepository implements ShortUrlRepositoryInterface
{
public function findOneWithDomainFallback(ShortUrlIdentifier $identifier, ShortUrlMode $shortUrlMode): ?ShortUrl
public function findOneWithDomainFallback(ShortUrlIdentifier $identifier, ShortUrlMode $shortUrlMode): ShortUrl|null
{
// When ordering DESC, Postgres puts nulls at the beginning while the rest of supported DB engines put them at
// the bottom
@ -52,7 +52,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
return $qb->getQuery()->getOneOrNullResult();
}
public function findOne(ShortUrlIdentifier $identifier, ?Specification $spec = null): ?ShortUrl
public function findOne(ShortUrlIdentifier $identifier, Specification|null $spec = null): ShortUrl|null
{
$qb = $this->createFindOneQueryBuilder($identifier, $spec);
$qb->select('s');
@ -60,12 +60,12 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
return $qb->getQuery()->getOneOrNullResult();
}
public function shortCodeIsInUse(ShortUrlIdentifier $identifier, ?Specification $spec = null): bool
public function shortCodeIsInUse(ShortUrlIdentifier $identifier, Specification|null $spec = null): bool
{
return $this->doShortCodeIsInUse($identifier, $spec, null);
}
public function shortCodeIsInUseWithLock(ShortUrlIdentifier $identifier, ?Specification $spec = null): bool
public function shortCodeIsInUseWithLock(ShortUrlIdentifier $identifier, Specification|null $spec = null): bool
{
return $this->doShortCodeIsInUse($identifier, $spec, LockMode::PESSIMISTIC_WRITE);
}
@ -73,8 +73,11 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
/**
* @param LockMode::PESSIMISTIC_WRITE|null $lockMode
*/
private function doShortCodeIsInUse(ShortUrlIdentifier $identifier, ?Specification $spec, ?LockMode $lockMode): bool
{
private function doShortCodeIsInUse(
ShortUrlIdentifier $identifier,
Specification|null $spec,
LockMode|null $lockMode,
): bool {
$qb = $this->createFindOneQueryBuilder($identifier, $spec)->select('s.id');
$query = $qb->getQuery();
@ -85,7 +88,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
return $query->getOneOrNullResult() !== null;
}
private function createFindOneQueryBuilder(ShortUrlIdentifier $identifier, ?Specification $spec): QueryBuilder
private function createFindOneQueryBuilder(ShortUrlIdentifier $identifier, Specification|null $spec): QueryBuilder
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->from(ShortUrl::class, 's')
@ -101,7 +104,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
return $qb;
}
public function findOneMatching(ShortUrlCreation $creation): ?ShortUrl
public function findOneMatching(ShortUrlCreation $creation): ShortUrl|null
{
$qb = $this->getEntityManager()->createQueryBuilder();
@ -166,7 +169,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
}
}
public function findOneByImportedUrl(ImportedShlinkUrl $url): ?ShortUrl
public function findOneByImportedUrl(ImportedShlinkUrl $url): ShortUrl|null
{
$qb = $this->createQueryBuilder('s');
$qb->andWhere($qb->expr()->eq('s.importOriginalShortCode', ':shortCode'))
@ -180,7 +183,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
return $qb->getQuery()->getOneOrNullResult();
}
private function whereDomainIs(QueryBuilder $qb, ?string $domain): void
private function whereDomainIs(QueryBuilder $qb, string|null $domain): void
{
if ($domain !== null) {
$qb->join('s.domain', 'd')

View File

@ -16,15 +16,18 @@ use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
/** @extends ObjectRepository<ShortUrl> */
interface ShortUrlRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
{
public function findOneWithDomainFallback(ShortUrlIdentifier $identifier, ShortUrlMode $shortUrlMode): ?ShortUrl;
public function findOneWithDomainFallback(
ShortUrlIdentifier $identifier,
ShortUrlMode $shortUrlMode,
): ShortUrl|null;
public function findOne(ShortUrlIdentifier $identifier, ?Specification $spec = null): ?ShortUrl;
public function findOne(ShortUrlIdentifier $identifier, Specification|null $spec = null): ShortUrl|null;
public function shortCodeIsInUse(ShortUrlIdentifier $identifier, ?Specification $spec = null): bool;
public function shortCodeIsInUse(ShortUrlIdentifier $identifier, Specification|null $spec = null): bool;
public function shortCodeIsInUseWithLock(ShortUrlIdentifier $identifier, ?Specification $spec = null): bool;
public function shortCodeIsInUseWithLock(ShortUrlIdentifier $identifier, Specification|null $spec = null): bool;
public function findOneMatching(ShortUrlCreation $creation): ?ShortUrl;
public function findOneMatching(ShortUrlCreation $creation): ShortUrl|null;
public function findOneByImportedUrl(ImportedShlinkUrl $url): ?ShortUrl;
public function findOneByImportedUrl(ImportedShlinkUrl $url): ShortUrl|null;
}

View File

@ -38,7 +38,7 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
$this->em->getEventManager()->addEventListener(Events::postFlush, $this);
}
public function resolveDomain(?string $domain): ?Domain
public function resolveDomain(string|null $domain): Domain|null
{
if ($domain === null || $domain === $this->options->defaultDomain) {
return null;

View File

@ -10,7 +10,7 @@ use Shlinkio\Shlink\Core\Tag\Entity\Tag;
interface ShortUrlRelationResolverInterface
{
public function resolveDomain(?string $domain): ?Domain;
public function resolveDomain(string|null $domain): Domain|null;
/**
* @param string[] $tags

View File

@ -12,7 +12,7 @@ use function array_map;
class SimpleShortUrlRelationResolver implements ShortUrlRelationResolverInterface
{
public function resolveDomain(?string $domain): ?Domain
public function resolveDomain(string|null $domain): Domain|null
{
return $domain !== null ? Domain::withAuthority($domain) : null;
}

View File

@ -22,7 +22,7 @@ readonly class ShortUrlListService implements ShortUrlListServiceInterface
/**
* @inheritDoc
*/
public function listShortUrls(ShortUrlsParams $params, ?ApiKey $apiKey = null): Paginator
public function listShortUrls(ShortUrlsParams $params, ApiKey|null $apiKey = null): Paginator
{
$defaultDomain = $this->urlShortenerOptions->defaultDomain;
$paginator = new Paginator(new ShortUrlRepositoryAdapter($this->repo, $params, $apiKey, $defaultDomain));

View File

@ -14,5 +14,5 @@ interface ShortUrlListServiceInterface
/**
* @return Paginator<ShortUrlWithVisitsSummary>
*/
public function listShortUrls(ShortUrlsParams $params, ?ApiKey $apiKey = null): Paginator;
public function listShortUrls(ShortUrlsParams $params, ApiKey|null $apiKey = null): Paginator;
}

View File

@ -23,7 +23,7 @@ readonly class ShortUrlResolver implements ShortUrlResolverInterface
/**
* @throws ShortUrlNotFoundException
*/
public function resolveShortUrl(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): ShortUrl
public function resolveShortUrl(ShortUrlIdentifier $identifier, ApiKey|null $apiKey = null): ShortUrl
{
/** @var ShortUrlRepository $shortUrlRepo */
$shortUrlRepo = $this->em->getRepository(ShortUrl::class);

View File

@ -14,7 +14,7 @@ interface ShortUrlResolverInterface
/**
* @throws ShortUrlNotFoundException
*/
public function resolveShortUrl(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): ShortUrl;
public function resolveShortUrl(ShortUrlIdentifier $identifier, ApiKey|null $apiKey = null): ShortUrl;
/**
* Resolves a public short URL matching provided identifier.

View File

@ -29,7 +29,7 @@ readonly class ShortUrlService implements ShortUrlServiceInterface
public function updateShortUrl(
ShortUrlIdentifier $identifier,
ShortUrlEdition $shortUrlEdit,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): ShortUrl {
if ($shortUrlEdit->longUrlWasProvided()) {
$shortUrlEdit = $this->titleResolutionHelper->processTitle($shortUrlEdit);

View File

@ -18,6 +18,6 @@ interface ShortUrlServiceInterface
public function updateShortUrl(
ShortUrlIdentifier $identifier,
ShortUrlEdition $shortUrlEdit,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): ShortUrl;
}

View File

@ -21,7 +21,7 @@ class ShortUrlVisitsDeleter implements ShortUrlVisitsDeleterInterface
/**
* @throws ShortUrlNotFoundException
*/
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): BulkDeleteResult
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ApiKey|null $apiKey = null): BulkDeleteResult
{
$shortUrl = $this->resolver->resolveShortUrl($identifier, $apiKey);
return new BulkDeleteResult($this->repository->deleteShortUrlVisits($shortUrl));

View File

@ -14,5 +14,5 @@ interface ShortUrlVisitsDeleterInterface
/**
* @throws ShortUrlNotFoundException
*/
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): BulkDeleteResult;
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ApiKey|null $apiKey = null): BulkDeleteResult;
}

View File

@ -11,7 +11,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class BelongsToApiKey extends BaseSpecification
{
public function __construct(private ApiKey $apiKey, ?string $context = null)
public function __construct(private ApiKey $apiKey, string|null $context = null)
{
parent::__construct($context);
}

View File

@ -10,7 +10,7 @@ use Happyr\DoctrineSpecification\Specification\BaseSpecification;
class BelongsToDomain extends BaseSpecification
{
public function __construct(private string $domainId, private ?string $dqlAlias = null)
public function __construct(private string $domainId, private string|null $dqlAlias = null)
{
parent::__construct();
}

View File

@ -64,7 +64,7 @@ class UrlShortener implements UrlShortenerInterface
return UrlShorteningResult::withoutErrorOnEventDispatching($newShortUrl);
}
private function findExistingShortUrlIfExists(ShortUrlCreation $creation): ?ShortUrl
private function findExistingShortUrlIfExists(ShortUrlCreation $creation): ShortUrl|null
{
if (! $creation->findIfExists) {
return null;

View File

@ -11,7 +11,7 @@ use Shlinkio\Shlink\Common\Util\DateRange;
class InDateRange extends BaseSpecification
{
public function __construct(private ?DateRange $dateRange, private string $field = 'date')
public function __construct(private DateRange|null $dateRange, private string $field = 'date')
{
parent::__construct();
}

View File

@ -11,7 +11,7 @@ enum OrderableField: string
case VISITS = 'visits';
case NON_BOT_VISITS = 'nonBotVisits';
public static function toValidField(?string $field): self
public static function toValidField(string|null $field): self
{
if ($field === null) {
return self::TAG;

View File

@ -15,7 +15,7 @@ final readonly class TagInfo implements JsonSerializable
public string $tag,
public int $shortUrlsCount,
int $visitsCount,
?int $nonBotVisitsCount = null,
int|null $nonBotVisitsCount = null,
) {
$this->visitsSummary = VisitsSummary::fromTotalAndNonBots($visitsCount, $nonBotVisitsCount ?? $visitsCount);
}

View File

@ -10,15 +10,15 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
final class TagsListFiltering
{
public function __construct(
public readonly ?int $limit = null,
public readonly ?int $offset = null,
public readonly ?string $searchTerm = null,
public readonly ?Ordering $orderBy = null,
public readonly ?ApiKey $apiKey = null,
public readonly int|null $limit = null,
public readonly int|null $offset = null,
public readonly string|null $searchTerm = null,
public readonly Ordering|null $orderBy = null,
public readonly ApiKey|null $apiKey = null,
) {
}
public static function fromRangeAndParams(int $limit, int $offset, TagsParams $params, ?ApiKey $apiKey): self
public static function fromRangeAndParams(int $limit, int $offset, TagsParams $params, ApiKey|null $apiKey): self
{
return new self($limit, $offset, $params->searchTerm, $params->orderBy, $apiKey);
}

View File

@ -12,10 +12,10 @@ use function Shlinkio\Shlink\Common\parseOrderBy;
final class TagsParams extends AbstractInfinitePaginableListParams
{
private function __construct(
public readonly ?string $searchTerm,
public readonly string|null $searchTerm,
public readonly Ordering $orderBy,
?int $page,
?int $itemsPerPage,
int|null $page,
int|null $itemsPerPage,
) {
parent::__construct($page, $itemsPerPage);
}

View File

@ -21,7 +21,7 @@ abstract class AbstractTagsPaginatorAdapter implements AdapterInterface
public function __construct(
protected TagRepositoryInterface $repo,
protected TagsParams $params,
protected ?ApiKey $apiKey,
protected ApiKey|null $apiKey,
) {
}

View File

@ -42,7 +42,7 @@ class TagRepository extends EntitySpecificationRepository implements TagReposito
/**
* @return TagInfo[]
*/
public function findTagsWithInfo(?TagsListFiltering $filtering = null): array
public function findTagsWithInfo(TagsListFiltering|null $filtering = null): array
{
$orderField = OrderableField::toValidField($filtering?->orderBy?->field);
$orderDir = $filtering?->orderBy?->direction ?? 'ASC';
@ -134,7 +134,7 @@ class TagRepository extends EntitySpecificationRepository implements TagReposito
);
}
public function tagExists(string $tag, ?ApiKey $apiKey = null): bool
public function tagExists(string $tag, ApiKey|null $apiKey = null): bool
{
$result = (int) $this->matchSingleScalarResult(Spec::andX(
new CountTagsWithName($tag),

View File

@ -19,7 +19,7 @@ interface TagRepositoryInterface extends ObjectRepository, EntitySpecificationRe
/**
* @return TagInfo[]
*/
public function findTagsWithInfo(?TagsListFiltering $filtering = null): array;
public function findTagsWithInfo(TagsListFiltering|null $filtering = null): array;
public function tagExists(string $tag, ?ApiKey $apiKey = null): bool;
public function tagExists(string $tag, ApiKey|null $apiKey = null): bool;
}

Some files were not shown because too many files have changed in this diff Show More