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

@@ -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;
}

View File

@@ -28,7 +28,7 @@ readonly class TagService implements TagServiceInterface
/**
* @inheritDoc
*/
public function listTags(TagsParams $params, ?ApiKey $apiKey = null): Paginator
public function listTags(TagsParams $params, ApiKey|null $apiKey = null): Paginator
{
/** @var TagRepository $repo */
$repo = $this->em->getRepository(Tag::class);
@@ -38,7 +38,7 @@ readonly class TagService implements TagServiceInterface
/**
* @inheritDoc
*/
public function tagsInfo(TagsParams $params, ?ApiKey $apiKey = null): Paginator
public function tagsInfo(TagsParams $params, ApiKey|null $apiKey = null): Paginator
{
/** @var TagRepositoryInterface $repo */
$repo = $this->em->getRepository(Tag::class);
@@ -60,7 +60,7 @@ readonly class TagService implements TagServiceInterface
/**
* @inheritDoc
*/
public function deleteTags(array $tagNames, ?ApiKey $apiKey = null): void
public function deleteTags(array $tagNames, ApiKey|null $apiKey = null): void
{
if (ApiKey::isShortUrlRestricted($apiKey)) {
throw ForbiddenTagOperationException::forDeletion();
@@ -74,7 +74,7 @@ readonly class TagService implements TagServiceInterface
/**
* @inheritDoc
*/
public function renameTag(TagRenaming $renaming, ?ApiKey $apiKey = null): Tag
public function renameTag(TagRenaming $renaming, ApiKey|null $apiKey = null): Tag
{
if (ApiKey::isShortUrlRestricted($apiKey)) {
throw ForbiddenTagOperationException::forRenaming();

View File

@@ -19,23 +19,23 @@ interface TagServiceInterface
/**
* @return Paginator<Tag>
*/
public function listTags(TagsParams $params, ?ApiKey $apiKey = null): Paginator;
public function listTags(TagsParams $params, ApiKey|null $apiKey = null): Paginator;
/**
* @return Paginator<TagInfo>
*/
public function tagsInfo(TagsParams $params, ?ApiKey $apiKey = null): Paginator;
public function tagsInfo(TagsParams $params, ApiKey|null $apiKey = null): Paginator;
/**
* @param string[] $tagNames
* @throws ForbiddenTagOperationException
*/
public function deleteTags(array $tagNames, ?ApiKey $apiKey = null): void;
public function deleteTags(array $tagNames, ApiKey|null $apiKey = null): void;
/**
* @throws TagNotFoundException
* @throws TagConflictException
* @throws ForbiddenTagOperationException
*/
public function renameTag(TagRenaming $renaming, ?ApiKey $apiKey = null): Tag;
public function renameTag(TagRenaming $renaming, ApiKey|null $apiKey = null): Tag;
}

View File

@@ -56,7 +56,7 @@ final class IpAddressUtils
*
* @param string[] $ipAddressParts
*/
private static function candidateToRange(string $candidate, array $ipAddressParts): ?RangeInterface
private static function candidateToRange(string $candidate, array $ipAddressParts): RangeInterface|null
{
return str_contains($candidate, '*')
? self::parseValueWithWildcards($candidate, $ipAddressParts)
@@ -68,7 +68,7 @@ final class IpAddressUtils
* Factory::parseRangeString can usually do this automatically, but only if wildcards are at the end. This also
* covers cases where wildcards are in between.
*/
private static function parseValueWithWildcards(string $value, array $ipAddressParts): ?RangeInterface
private static function parseValueWithWildcards(string $value, array $ipAddressParts): RangeInterface|null
{
$octets = explode('.', $value);
$keys = array_keys($octets);

View File

@@ -21,14 +21,14 @@ use function Shlinkio\Shlink\Core\normalizeDate;
class Visit extends AbstractEntity implements JsonSerializable
{
private function __construct(
public readonly ?ShortUrl $shortUrl,
public readonly ShortUrl|null $shortUrl,
public readonly VisitType $type,
public readonly string $userAgent,
public readonly string $referer,
public readonly bool $potentialBot,
public readonly ?string $remoteAddr = null,
public readonly ?string $visitedUrl = null,
private ?VisitLocation $visitLocation = null,
public readonly string|null $remoteAddr = null,
public readonly string|null $visitedUrl = null,
private VisitLocation|null $visitLocation = null,
public readonly Chronos $date = new Chronos(),
) {
}
@@ -53,8 +53,12 @@ class Visit extends AbstractEntity implements JsonSerializable
return self::fromVisitor(null, VisitType::REGULAR_404, $visitor, $anonymize);
}
private static function fromVisitor(?ShortUrl $shortUrl, VisitType $type, Visitor $visitor, bool $anonymize): self
{
private static function fromVisitor(
ShortUrl|null $shortUrl,
VisitType $type,
Visitor $visitor,
bool $anonymize,
): self {
return new self(
shortUrl: $shortUrl,
type: $type,
@@ -66,7 +70,7 @@ class Visit extends AbstractEntity implements JsonSerializable
);
}
private static function processAddress(?string $address, bool $anonymize): ?string
private static function processAddress(string|null $address, bool $anonymize): string|null
{
// Localhost address does not need to be anonymized
if (! $anonymize || $address === null || $address === IpAddress::LOCALHOST) {
@@ -96,7 +100,7 @@ class Visit extends AbstractEntity implements JsonSerializable
private static function fromImportOrOrphanImport(
ImportedShlinkVisit|ImportedShlinkOrphanVisit $importedVisit,
VisitType $type,
?ShortUrl $shortUrl = null,
ShortUrl|null $shortUrl = null,
): self {
$importedLocation = $importedVisit->location;
return new self(
@@ -116,7 +120,7 @@ class Visit extends AbstractEntity implements JsonSerializable
return ! empty($this->remoteAddr);
}
public function getVisitLocation(): ?VisitLocation
public function getVisitLocation(): VisitLocation|null
{
return $this->visitLocation;
}

View File

@@ -12,11 +12,11 @@ use function sprintf;
final class OrphanVisitsParams extends VisitsParams
{
public function __construct(
?DateRange $dateRange = null,
?int $page = null,
?int $itemsPerPage = null,
DateRange|null $dateRange = null,
int|null $page = null,
int|null $itemsPerPage = null,
bool $excludeBots = false,
public readonly ?OrphanVisitType $type = null,
public readonly OrphanVisitType|null $type = null,
) {
parent::__construct($dateRange, $page, $itemsPerPage, $excludeBots);
}

View File

@@ -21,10 +21,10 @@ final class Visitor
public readonly string $userAgent;
public readonly string $referer;
public readonly string $visitedUrl;
public readonly ?string $remoteAddress;
public readonly string|null $remoteAddress;
private bool $potentialBot;
public function __construct(string $userAgent, string $referer, ?string $remoteAddress, string $visitedUrl)
public function __construct(string $userAgent, string $referer, string|null $remoteAddress, string $visitedUrl)
{
$this->userAgent = $this->cropToLength($userAgent, self::USER_AGENT_MAX_LENGTH);
$this->referer = $this->cropToLength($referer, self::REFERER_MAX_LENGTH);

View File

@@ -14,9 +14,9 @@ class VisitsParams extends AbstractInfinitePaginableListParams
public readonly DateRange $dateRange;
public function __construct(
?DateRange $dateRange = null,
?int $page = null,
?int $itemsPerPage = null,
DateRange|null $dateRange = null,
int|null $page = null,
int|null $itemsPerPage = null,
public readonly bool $excludeBots = false,
) {
parent::__construct($page, $itemsPerPage);

View File

@@ -14,8 +14,8 @@ final readonly class VisitsStats implements JsonSerializable
public function __construct(
int $nonOrphanVisitsTotal,
int $orphanVisitsTotal,
?int $nonOrphanVisitsNonBots = null,
?int $orphanVisitsNonBots = null,
int|null $nonOrphanVisitsNonBots = null,
int|null $orphanVisitsNonBots = null,
) {
$this->nonOrphanVisitsSummary = VisitsSummary::fromTotalAndNonBots(
$nonOrphanVisitsTotal,

View File

@@ -21,7 +21,7 @@ class DomainVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
private readonly VisitRepositoryInterface $visitRepository,
private readonly string $domain,
private readonly VisitsParams $params,
private readonly ?ApiKey $apiKey,
private readonly ApiKey|null $apiKey,
) {
}

View File

@@ -18,7 +18,7 @@ class NonOrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAda
public function __construct(
private readonly VisitRepositoryInterface $repo,
private readonly VisitsParams $params,
private readonly ?ApiKey $apiKey,
private readonly ApiKey|null $apiKey,
) {
}

View File

@@ -18,7 +18,7 @@ class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapte
public function __construct(
private readonly VisitRepositoryInterface $repo,
private readonly OrphanVisitsParams $params,
private readonly ?ApiKey $apiKey,
private readonly ApiKey|null $apiKey,
) {
}

View File

@@ -20,7 +20,7 @@ class ShortUrlVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdap
private readonly VisitRepositoryInterface $visitRepository,
private readonly ShortUrlIdentifier $identifier,
private readonly VisitsParams $params,
private readonly ?ApiKey $apiKey,
private readonly ApiKey|null $apiKey,
) {
}

View File

@@ -19,7 +19,7 @@ class TagVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
private readonly VisitRepositoryInterface $visitRepository,
private readonly string $tag,
private readonly VisitsParams $params,
private readonly ?ApiKey $apiKey,
private readonly ApiKey|null $apiKey,
) {
}

View File

@@ -11,10 +11,10 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class OrphanVisitsCountFiltering extends VisitsCountFiltering
{
public function __construct(
?DateRange $dateRange = null,
DateRange|null $dateRange = null,
bool $excludeBots = false,
?ApiKey $apiKey = null,
public readonly ?OrphanVisitType $type = null,
ApiKey|null $apiKey = null,
public readonly OrphanVisitType|null $type = null,
) {
parent::__construct($dateRange, $excludeBots, $apiKey);
}

View File

@@ -11,12 +11,12 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
final class OrphanVisitsListFiltering extends OrphanVisitsCountFiltering
{
public function __construct(
?DateRange $dateRange = null,
DateRange|null $dateRange = null,
bool $excludeBots = false,
?ApiKey $apiKey = null,
?OrphanVisitType $type = null,
public readonly ?int $limit = null,
public readonly ?int $offset = null,
ApiKey|null $apiKey = null,
OrphanVisitType|null $type = null,
public readonly int|null $limit = null,
public readonly int|null $offset = null,
) {
parent::__construct($dateRange, $excludeBots, $apiKey, $type);
}

View File

@@ -10,9 +10,9 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class VisitsCountFiltering
{
public function __construct(
public readonly ?DateRange $dateRange = null,
public readonly DateRange|null $dateRange = null,
public readonly bool $excludeBots = false,
public readonly ?ApiKey $apiKey = null,
public readonly ApiKey|null $apiKey = null,
) {
}
}

View File

@@ -10,11 +10,11 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
final class VisitsListFiltering extends VisitsCountFiltering
{
public function __construct(
?DateRange $dateRange = null,
DateRange|null $dateRange = null,
bool $excludeBots = false,
?ApiKey $apiKey = null,
public readonly ?int $limit = null,
public readonly ?int $offset = null,
ApiKey|null $apiKey = null,
public readonly int|null $limit = null,
public readonly int|null $offset = null,
) {
parent::__construct($dateRange, $excludeBots, $apiKey);
}

View File

@@ -48,7 +48,7 @@ class VisitIterationRepository extends EntitySpecificationRepository implements
/**
* @return iterable<Visit>
*/
public function findAllVisits(?DateRange $dateRange = null, int $blockSize = self::DEFAULT_BLOCK_SIZE): iterable
public function findAllVisits(DateRange|null $dateRange = null, int $blockSize = self::DEFAULT_BLOCK_SIZE): iterable
{
$qb = $this->createQueryBuilder('v');
if ($dateRange?->startDate !== null) {

View File

@@ -24,5 +24,8 @@ interface VisitIterationRepositoryInterface
/**
* @return iterable<Visit>
*/
public function findAllVisits(?DateRange $dateRange = null, int $blockSize = self::DEFAULT_BLOCK_SIZE): iterable;
public function findAllVisits(
DateRange|null $dateRange = null,
int $blockSize = self::DEFAULT_BLOCK_SIZE,
): iterable;
}

View File

@@ -203,7 +203,7 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
return $qb;
}
private function applyDatesInline(QueryBuilder $qb, ?DateRange $dateRange): void
private function applyDatesInline(QueryBuilder $qb, DateRange|null $dateRange): void
{
$conn = $this->getEntityManager()->getConnection();
@@ -215,7 +215,7 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
}
}
private function resolveVisitsWithNativeQuery(QueryBuilder $qb, ?int $limit, ?int $offset): array
private function resolveVisitsWithNativeQuery(QueryBuilder $qb, int|null $limit, int|null $offset): array
{
// TODO Order by date and ID, not just by ID (order by date DESC, id DESC).
// That ensures imported visits are properly ordered even if inserted in wrong chronological order.
@@ -248,7 +248,7 @@ class VisitRepository extends EntitySpecificationRepository implements VisitRepo
return $this->getEntityManager()->createNativeQuery($nativeQb->getSQL(), $rsm)->getResult();
}
public function findMostRecentOrphanVisit(): ?Visit
public function findMostRecentOrphanVisit(): Visit|null
{
$dql = <<<DQL
SELECT v

View File

@@ -53,5 +53,5 @@ interface VisitRepositoryInterface extends ObjectRepository, EntitySpecification
public function countNonOrphanVisits(VisitsCountFiltering $filtering): int;
public function findMostRecentOrphanVisit(): ?Visit;
public function findMostRecentOrphanVisit(): Visit|null;
}

View File

@@ -63,7 +63,7 @@ readonly class RequestTracker implements RequestTrackerInterface, RequestMethodI
return ! $this->trackingOptions->queryHasDisableTrackParam($query);
}
private function shouldDisableTrackingFromAddress(?string $remoteAddr): bool
private function shouldDisableTrackingFromAddress(string|null $remoteAddr): bool
{
if ($remoteAddr === null || ! $this->trackingOptions->hasDisableTrackingFrom()) {
return false;

View File

@@ -15,7 +15,7 @@ class VisitsDeleter implements VisitsDeleterInterface
{
}
public function deleteOrphanVisits(?ApiKey $apiKey = null): BulkDeleteResult
public function deleteOrphanVisits(ApiKey|null $apiKey = null): BulkDeleteResult
{
$affectedItems = $apiKey?->hasRole(Role::NO_ORPHAN_VISITS) ? 0 : $this->repository->deleteOrphanVisits();
return new BulkDeleteResult($affectedItems);

View File

@@ -9,5 +9,5 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
interface VisitsDeleterInterface
{
public function deleteOrphanVisits(?ApiKey $apiKey = null): BulkDeleteResult;
public function deleteOrphanVisits(ApiKey|null $apiKey = null): BulkDeleteResult;
}

View File

@@ -41,7 +41,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
{
}
public function getVisitsStats(?ApiKey $apiKey = null): VisitsStats
public function getVisitsStats(ApiKey|null $apiKey = null): VisitsStats
{
/** @var OrphanVisitsCountRepository $orphanVisitsCountRepo */
$orphanVisitsCountRepo = $this->em->getRepository(OrphanVisitsCount::class);
@@ -68,7 +68,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
public function visitsForShortUrl(
ShortUrlIdentifier $identifier,
VisitsParams $params,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): Paginator {
/** @var ShortUrlRepositoryInterface $repo */
$repo = $this->em->getRepository(ShortUrl::class);
@@ -88,7 +88,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
/**
* @inheritDoc
*/
public function visitsForTag(string $tag, VisitsParams $params, ?ApiKey $apiKey = null): Paginator
public function visitsForTag(string $tag, VisitsParams $params, ApiKey|null $apiKey = null): Paginator
{
/** @var TagRepository $tagRepo */
$tagRepo = $this->em->getRepository(Tag::class);
@@ -105,7 +105,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
/**
* @inheritDoc
*/
public function visitsForDomain(string $domain, VisitsParams $params, ?ApiKey $apiKey = null): Paginator
public function visitsForDomain(string $domain, VisitsParams $params, ApiKey|null $apiKey = null): Paginator
{
/** @var DomainRepository $domainRepo */
$domainRepo = $this->em->getRepository(Domain::class);
@@ -122,7 +122,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
/**
* @inheritDoc
*/
public function orphanVisits(OrphanVisitsParams $params, ?ApiKey $apiKey = null): Paginator
public function orphanVisits(OrphanVisitsParams $params, ApiKey|null $apiKey = null): Paginator
{
/** @var VisitRepositoryInterface $repo */
$repo = $this->em->getRepository(Visit::class);
@@ -130,7 +130,7 @@ readonly class VisitsStatsHelper implements VisitsStatsHelperInterface
return $this->createPaginator(new OrphanVisitsPaginatorAdapter($repo, $params, $apiKey), $params);
}
public function nonOrphanVisits(VisitsParams $params, ?ApiKey $apiKey = null): Paginator
public function nonOrphanVisits(VisitsParams $params, ApiKey|null $apiKey = null): Paginator
{
/** @var VisitRepositoryInterface $repo */
$repo = $this->em->getRepository(Visit::class);

View File

@@ -17,7 +17,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
interface VisitsStatsHelperInterface
{
public function getVisitsStats(?ApiKey $apiKey = null): VisitsStats;
public function getVisitsStats(ApiKey|null $apiKey = null): VisitsStats;
/**
* @return Paginator<Visit>
@@ -26,28 +26,28 @@ interface VisitsStatsHelperInterface
public function visitsForShortUrl(
ShortUrlIdentifier $identifier,
VisitsParams $params,
?ApiKey $apiKey = null,
ApiKey|null $apiKey = null,
): Paginator;
/**
* @return Paginator<Visit>
* @throws TagNotFoundException
*/
public function visitsForTag(string $tag, VisitsParams $params, ?ApiKey $apiKey = null): Paginator;
public function visitsForTag(string $tag, VisitsParams $params, ApiKey|null $apiKey = null): Paginator;
/**
* @return Paginator<Visit>
* @throws DomainNotFoundException
*/
public function visitsForDomain(string $domain, VisitsParams $params, ?ApiKey $apiKey = null): Paginator;
public function visitsForDomain(string $domain, VisitsParams $params, ApiKey|null $apiKey = null): Paginator;
/**
* @return Paginator<Visit>
*/
public function orphanVisits(OrphanVisitsParams $params, ?ApiKey $apiKey = null): Paginator;
public function orphanVisits(OrphanVisitsParams $params, ApiKey|null $apiKey = null): Paginator;
/**
* @return Paginator<Visit>
*/
public function nonOrphanVisits(VisitsParams $params, ?ApiKey $apiKey = null): Paginator;
public function nonOrphanVisits(VisitsParams $params, ApiKey|null $apiKey = null): Paginator;
}