Drop support for PHP 8.2

This commit is contained in:
Alejandro Celaya
2024-12-02 09:13:20 +01:00
parent bfaab6c494
commit 58de998596
110 changed files with 232 additions and 224 deletions

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.2', '8.3', '8.4']
php-version: ['8.3', '8.4']
env:
LC_ALL: C
steps:

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.2', '8.3', '8.4']
php-version: ['8.3', '8.4']
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # rr get-binary picks this env automatically
steps:

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.2', '8.3', '8.4']
php-version: ['8.3', '8.4']
steps:
- uses: actions/checkout@v4
- uses: './.github/actions/ci-setup'

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
php-version: ['8.2']
php-version: ['8.3']
steps:
- uses: actions/checkout@v4
- name: Determine version

View File

@@ -21,7 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
* *Nothing*
### Removed
* *Nothing*
* * [#2247](https://github.com/shlinkio/shlink/issues/2247) Drop support for PHP 8.2
### Fixed
* *Nothing*

View File

@@ -36,7 +36,7 @@ The idea is that you can just generate a container using the image and provide t
First, make sure the host where you are going to run shlink fulfills these requirements:
* PHP 8.2 or 8.3
* PHP 8.3 or 8.4
* The next PHP extensions: json, curl, pdo, intl, gd and gmp/bcmath.
* apcu extension is recommended if you don't plan to use RoadRunner.
* xml extension is required if you want to generate QR codes in svg format.

View File

@@ -12,7 +12,7 @@
}
],
"require": {
"php": "^8.2",
"php": "^8.3",
"ext-curl": "*",
"ext-gd": "*",
"ext-json": "*",

View File

@@ -20,7 +20,7 @@ use function sprintf;
class DisableKeyCommand extends Command
{
public const NAME = 'api-key:disable';
public const string NAME = 'api-key:disable';
public function __construct(private readonly ApiKeyServiceInterface $apiKeyService)
{

View File

@@ -23,7 +23,7 @@ use function sprintf;
class GenerateKeyCommand extends Command
{
public const NAME = 'api-key:generate';
public const string NAME = 'api-key:generate';
public function __construct(
private readonly ApiKeyServiceInterface $apiKeyService,

View File

@@ -13,7 +13,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class InitialApiKeyCommand extends Command
{
public const NAME = 'api-key:initial';
public const string NAME = 'api-key:initial';
public function __construct(private readonly ApiKeyServiceInterface $apiKeyService)
{

View File

@@ -21,11 +21,11 @@ use function sprintf;
class ListKeysCommand extends Command
{
private const ERROR_STRING_PATTERN = '<fg=red>%s</>';
private const SUCCESS_STRING_PATTERN = '<info>%s</info>';
private const WARNING_STRING_PATTERN = '<comment>%s</comment>';
private const string ERROR_STRING_PATTERN = '<fg=red>%s</>';
private const string SUCCESS_STRING_PATTERN = '<info>%s</info>';
private const string WARNING_STRING_PATTERN = '<comment>%s</comment>';
public const NAME = 'api-key:list';
public const string NAME = 'api-key:list';
public function __construct(private readonly ApiKeyServiceInterface $apiKeyService)
{

View File

@@ -19,7 +19,7 @@ use function Shlinkio\Shlink\Core\ArrayUtils\map;
class RenameApiKeyCommand extends Command
{
public const NAME = 'api-key:rename';
public const string NAME = 'api-key:rename';
public function __construct(private readonly ApiKeyServiceInterface $apiKeyService)
{

View File

@@ -21,7 +21,7 @@ use function sprintf;
class ReadEnvVarCommand extends Command
{
public const NAME = 'env-var:read';
public const string NAME = 'env-var:read';
/** @var Closure(string $envVar): mixed */
private readonly Closure $loadEnvVar;

View File

@@ -24,9 +24,9 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
{
private readonly Connection $regularConn;
public const NAME = 'db:create';
public const DOCTRINE_SCRIPT = 'bin/doctrine';
public const DOCTRINE_CREATE_SCHEMA_COMMAND = 'orm:schema-tool:create';
public const string NAME = 'db:create';
public const string DOCTRINE_SCRIPT = 'bin/doctrine';
public const string DOCTRINE_CREATE_SCHEMA_COMMAND = 'orm:schema-tool:create';
public function __construct(
LockFactory $locker,

View File

@@ -11,9 +11,9 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateDatabaseCommand extends AbstractDatabaseCommand
{
public const NAME = 'db:migrate';
public const DOCTRINE_MIGRATIONS_SCRIPT = 'vendor/doctrine/migrations/bin/doctrine-migrations.php';
public const DOCTRINE_MIGRATE_COMMAND = 'migrations:migrate';
public const string NAME = 'db:migrate';
public const string DOCTRINE_MIGRATIONS_SCRIPT = 'vendor/doctrine/migrations/bin/doctrine-migrations.php';
public const string DOCTRINE_MIGRATE_COMMAND = 'migrations:migrate';
protected function configure(): void
{

View File

@@ -21,7 +21,7 @@ use function str_contains;
class DomainRedirectsCommand extends Command
{
public const NAME = 'domain:redirects';
public const string NAME = 'domain:redirects';
public function __construct(private readonly DomainServiceInterface $domainService)
{

View File

@@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputInterface;
class GetDomainVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'domain:visits';
public const string NAME = 'domain:visits';
public function __construct(
VisitsStatsHelperInterface $visitsHelper,

View File

@@ -18,7 +18,7 @@ use function array_map;
class ListDomainsCommand extends Command
{
public const NAME = 'domain:list';
public const string NAME = 'domain:list';
public function __construct(private readonly DomainServiceInterface $domainService)
{

View File

@@ -22,7 +22,7 @@ use function sprintf;
class MatomoSendVisitsCommand extends Command implements VisitSendingProgressTrackerInterface
{
public const NAME = 'integration:matomo:send-visits';
public const string NAME = 'integration:matomo:send-visits';
private readonly bool $matomoEnabled;
private SymfonyStyle $io;

View File

@@ -19,7 +19,7 @@ use function sprintf;
class ManageRedirectRulesCommand extends Command
{
public const NAME = 'short-url:manage-rules';
public const string NAME = 'short-url:manage-rules';
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;

View File

@@ -20,7 +20,7 @@ use function sprintf;
class CreateShortUrlCommand extends Command
{
public const NAME = 'short-url:create';
public const string NAME = 'short-url:create';
private SymfonyStyle $io;
private readonly ShortUrlDataInput $shortUrlDataInput;

View File

@@ -17,7 +17,7 @@ use function sprintf;
class DeleteExpiredShortUrlsCommand extends Command
{
public const NAME = 'short-url:delete-expired';
public const string NAME = 'short-url:delete-expired';
public function __construct(private readonly DeleteShortUrlServiceInterface $deleteShortUrlService)
{

View File

@@ -19,7 +19,7 @@ use function sprintf;
class DeleteShortUrlCommand extends Command
{
public const NAME = 'short-url:delete';
public const string NAME = 'short-url:delete';
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;

View File

@@ -16,7 +16,7 @@ use function sprintf;
class DeleteShortUrlVisitsCommand extends AbstractDeleteVisitsCommand
{
public const NAME = 'short-url:visits-delete';
public const string NAME = 'short-url:visits-delete';
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;

View File

@@ -19,7 +19,7 @@ use function sprintf;
class EditShortUrlCommand extends Command
{
public const NAME = 'short-url:edit';
public const string NAME = 'short-url:edit';
private readonly ShortUrlDataInput $shortUrlDataInput;
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;

View File

@@ -16,7 +16,7 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class GetShortUrlVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'short-url:visits';
public const string NAME = 'short-url:visits';
private ShortUrlIdentifierInput $shortUrlIdentifierInput;

View File

@@ -33,7 +33,7 @@ use function sprintf;
class ListShortUrlsCommand extends Command
{
public const NAME = 'short-url:list';
public const string NAME = 'short-url:list';
private readonly StartDateOption $startDateOption;
private readonly EndDateOption $endDateOption;

View File

@@ -17,7 +17,7 @@ use function sprintf;
class ResolveUrlCommand extends Command
{
public const NAME = 'short-url:parse';
public const string NAME = 'short-url:parse';
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;

View File

@@ -14,9 +14,9 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class DeleteTagsCommand extends Command
{
public const NAME = 'tag:delete';
public const string NAME = 'tag:delete';
public function __construct(private TagServiceInterface $tagService)
public function __construct(private readonly TagServiceInterface $tagService)
{
parent::__construct();
}

View File

@@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputInterface;
class GetTagVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'tag:visits';
public const string NAME = 'tag:visits';
public function __construct(
VisitsStatsHelperInterface $visitsHelper,

View File

@@ -17,7 +17,7 @@ use function array_map;
class ListTagsCommand extends Command
{
public const NAME = 'tag:list';
public const string NAME = 'tag:list';
public function __construct(private readonly TagServiceInterface $tagService)
{

View File

@@ -17,7 +17,7 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class RenameTagCommand extends Command
{
public const NAME = 'tag:rename';
public const string NAME = 'tag:rename';
public function __construct(private readonly TagServiceInterface $tagService)
{

View File

@@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Util;
final class LockedCommandConfig
{
public const DEFAULT_TTL = 600.0; // 10 minutes
public const float DEFAULT_TTL = 600.0; // 10 minutes
private function __construct(
public readonly string $lockName,

View File

@@ -13,7 +13,7 @@ use function sprintf;
class DeleteOrphanVisitsCommand extends AbstractDeleteVisitsCommand
{
public const NAME = 'visit:orphan-delete';
public const string NAME = 'visit:orphan-delete';
public function __construct(private readonly VisitsDeleterInterface $deleter)
{

View File

@@ -18,7 +18,7 @@ use function sprintf;
class DownloadGeoLiteDbCommand extends Command
{
public const NAME = 'visit:download-db';
public const string NAME = 'visit:download-db';
private ProgressBar|null $progressBar = null;

View File

@@ -14,7 +14,7 @@ use Symfony\Component\Console\Input\InputInterface;
class GetNonOrphanVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'visit:non-orphan';
public const string NAME = 'visit:non-orphan';
public function __construct(
VisitsStatsHelperInterface $visitsHelper,

View File

@@ -17,7 +17,7 @@ use function sprintf;
class GetOrphanVisitsCommand extends AbstractVisitsListCommand
{
public const NAME = 'visit:orphan';
public const string NAME = 'visit:orphan';
protected function configure(): void
{

View File

@@ -29,7 +29,7 @@ use function sprintf;
class LocateVisitsCommand extends AbstractLockedCommand implements VisitGeolocationHelperInterface
{
public const NAME = 'visit:locate';
public const string NAME = 'visit:locate';
private SymfonyStyle $io;

View File

@@ -20,7 +20,7 @@ use function is_int;
class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
{
private const LOCK_NAME = 'geolocation-db-update';
private const string LOCK_NAME = 'geolocation-db-update';
/** @var Closure(): Reader */
private readonly Closure $geoLiteDbReaderFactory;

View File

@@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Util;
final class ExitCode
{
public const EXIT_SUCCESS = 0;
public const EXIT_FAILURE = -1;
public const EXIT_WARNING = 1;
public const int EXIT_SUCCESS = 0;
public const int EXIT_FAILURE = -1;
public const int EXIT_WARNING = 1;
}

View File

@@ -12,8 +12,8 @@ use function array_pop;
final class ShlinkTable
{
private const DEFAULT_STYLE_NAME = 'default';
private const TABLE_TITLE_STYLE = '<options=bold> %s </>';
private const string DEFAULT_STYLE_NAME = 'default';
private const string TABLE_TITLE_STYLE = '<options=bold> %s </>';
private function __construct(private readonly Table $baseTable, private readonly bool $withRowSeparators = false)
{

View File

@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
final class Version20230211171904 extends AbstractMigration
{
private const INDEX_NAME = 'IDX_visits_potential_bot';
private const string INDEX_NAME = 'IDX_visits_potential_bot';
public function up(Schema $schema): void
{

View File

@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
final class Version20230303164233 extends AbstractMigration
{
private const INDEX_NAME = 'visits_potential_bot_IDX';
private const string INDEX_NAME = 'visits_potential_bot_IDX';
public function up(Schema $schema): void
{

View File

@@ -17,8 +17,12 @@ use function in_array;
*/
final class Version20240220214031 extends AbstractMigration
{
private const DOMAINS_COLUMNS = ['base_url_redirect', 'regular_not_found_redirect', 'invalid_short_url_redirect'];
private const TEXT_COLUMNS = [
private const array DOMAINS_COLUMNS = [
'base_url_redirect',
'regular_not_found_redirect',
'invalid_short_url_redirect',
];
private const array TEXT_COLUMNS = [
'domains' => self::DOMAINS_COLUMNS,
'short_urls' => ['original_url'],
];

View File

@@ -11,7 +11,7 @@ use Doctrine\Migrations\AbstractMigration;
final class Version20241124112257 extends AbstractMigration
{
private const COLUMN_NAME = 'redirect_url';
private const string COLUMN_NAME = 'redirect_url';
public function up(Schema $schema): void
{

View File

@@ -30,9 +30,9 @@ use const Shlinkio\Shlink\DEFAULT_QR_CODE_COLOR;
final class QrCodeParams
{
private const MIN_SIZE = 50;
private const MAX_SIZE = 1000;
private const SUPPORTED_FORMATS = ['png', 'svg'];
private const int MIN_SIZE = 50;
private const int MAX_SIZE = 1000;
private const array SUPPORTED_FORMATS = ['png', 'svg'];
private function __construct(
public readonly int $size,

View File

@@ -17,8 +17,8 @@ use function urlencode;
class NotFoundRedirectResolver implements NotFoundRedirectResolverInterface
{
private const DOMAIN_PLACEHOLDER = '{DOMAIN}';
private const ORIGINAL_PATH_PLACEHOLDER = '{ORIGINAL_PATH}';
private const string DOMAIN_PLACEHOLDER = '{DOMAIN}';
private const string ORIGINAL_PATH_PLACEHOLDER = '{ORIGINAL_PATH}';
public function __construct(
private readonly RedirectResponseHelperInterface $redirectResponseHelper,

View File

@@ -8,7 +8,7 @@ use function array_map;
class BasePathPrefixer
{
private const ELEMENTS_WITH_PATH = ['routes', 'middleware_pipeline'];
private const array ELEMENTS_WITH_PATH = ['routes', 'middleware_pipeline'];
public function __invoke(array $config): array
{

View File

@@ -11,8 +11,8 @@ use function str_replace;
class MultiSegmentSlugProcessor
{
private const SINGLE_SEGMENT_PATTERN = '{shortCode}';
private const MULTI_SEGMENT_PATTERN = '{shortCode:.+}';
private const string SINGLE_SEGMENT_PATTERN = '{shortCode}';
private const string MULTI_SEGMENT_PATTERN = '{shortCode:.+}';
public function __invoke(array $config): array
{

View File

@@ -11,7 +11,7 @@ use Shlinkio\Shlink\Core\Config\NotFoundRedirects;
class Domain extends AbstractEntity implements JsonSerializable, NotFoundRedirectConfigInterface
{
public const DEFAULT_AUTHORITY = 'DEFAULT';
public const string DEFAULT_AUTHORITY = 'DEFAULT';
private function __construct(
public readonly string $authority,

View File

@@ -11,10 +11,10 @@ use Shlinkio\Shlink\Common\Validation\InputFactory;
/** @extends InputFilter<mixed> */
class DomainRedirectsInputFilter extends InputFilter
{
public const DOMAIN = 'domain';
public const BASE_URL_REDIRECT = 'baseUrlRedirect';
public const REGULAR_404_REDIRECT = 'regular404Redirect';
public const INVALID_SHORT_URL_REDIRECT = 'invalidShortUrlRedirect';
public const string DOMAIN = 'domain';
public const string BASE_URL_REDIRECT = 'baseUrlRedirect';
public const string REGULAR_404_REDIRECT = 'regular404Redirect';
public const string INVALID_SHORT_URL_REDIRECT = 'invalidShortUrlRedirect';
private function __construct()
{

View File

@@ -17,9 +17,9 @@ use function sprintf;
class NotFoundTemplateHandler implements RequestHandlerInterface
{
private const TEMPLATES_BASE_DIR = __DIR__ . '/../../templates';
public const NOT_FOUND_TEMPLATE = '404.html';
public const INVALID_SHORT_CODE_TEMPLATE = 'invalid-short-code.html';
private const string TEMPLATES_BASE_DIR = __DIR__ . '/../../templates';
public const string NOT_FOUND_TEMPLATE = '404.html';
public const string INVALID_SHORT_CODE_TEMPLATE = 'invalid-short-code.html';
private Closure $readFile;

View File

@@ -16,8 +16,8 @@ class DeleteShortUrlException extends DomainException implements ProblemDetailsE
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Cannot delete short URL';
public const ERROR_CODE = 'invalid-short-url-deletion';
private const string TITLE = 'Cannot delete short URL';
public const string ERROR_CODE = 'invalid-short-url-deletion';
public static function fromVisitsThreshold(int $threshold, ShortUrlIdentifier $identifier): self
{

View File

@@ -15,8 +15,8 @@ class DomainNotFoundException extends DomainException implements ProblemDetailsE
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Domain not found';
public const ERROR_CODE = 'domain-not-found';
private const string TITLE = 'Domain not found';
public const string ERROR_CODE = 'domain-not-found';
private function __construct(string $message, array $additional)
{

View File

@@ -14,8 +14,8 @@ class ForbiddenTagOperationException extends DomainException implements ProblemD
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Forbidden tag operation';
public const ERROR_CODE = 'forbidden-tag-operation';
private const string TITLE = 'Forbidden tag operation';
public const string ERROR_CODE = 'forbidden-tag-operation';
public static function forDeletion(): self
{

View File

@@ -16,8 +16,8 @@ class NonUniqueSlugException extends InvalidArgumentException implements Problem
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Invalid custom slug';
public const ERROR_CODE = 'non-unique-slug';
private const string TITLE = 'Invalid custom slug';
public const string ERROR_CODE = 'non-unique-slug';
public static function fromSlug(string $slug, string|null $domain = null): self
{

View File

@@ -16,8 +16,8 @@ class ShortUrlNotFoundException extends DomainException implements ProblemDetail
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Short URL not found';
public const ERROR_CODE = 'short-url-not-found';
private const string TITLE = 'Short URL not found';
public const string ERROR_CODE = 'short-url-not-found';
public static function fromNotFound(ShortUrlIdentifier $identifier): self
{

View File

@@ -16,8 +16,8 @@ class TagConflictException extends RuntimeException implements ProblemDetailsExc
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Tag conflict';
public const ERROR_CODE = 'tag-conflict';
private const string TITLE = 'Tag conflict';
public const string ERROR_CODE = 'tag-conflict';
public static function forExistingTag(Renaming $renaming): self
{

View File

@@ -15,8 +15,8 @@ class TagNotFoundException extends DomainException implements ProblemDetailsExce
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Tag not found';
public const ERROR_CODE = 'tag-not-found';
private const string TITLE = 'Tag not found';
public const string ERROR_CODE = 'tag-not-found';
public static function fromTag(string $tag): self
{

View File

@@ -21,8 +21,8 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
{
use CommonProblemDetailsExceptionTrait;
private const TITLE = 'Invalid data';
public const ERROR_CODE = 'invalid-data';
private const string TITLE = 'Invalid data';
public const string ERROR_CODE = 'invalid-data';
private array $invalidElements;

View File

@@ -9,7 +9,7 @@ use Shlinkio\Shlink\Core\Exception\RuntimeException;
readonly class MatomoTrackerBuilder implements MatomoTrackerBuilderInterface
{
public const MATOMO_DEFAULT_TIMEOUT = 10; // Time in seconds
public const int MATOMO_DEFAULT_TIMEOUT = 10; // Time in seconds
public function __construct(private MatomoOptions $options)
{

View File

@@ -6,9 +6,9 @@ namespace Shlinkio\Shlink\Core\Model;
final readonly class Ordering
{
private const DESC_DIR = 'DESC';
private const ASC_DIR = 'ASC';
private const DEFAULT_DIR = self::ASC_DIR;
private const string DESC_DIR = 'DESC';
private const string ASC_DIR = 'ASC';
private const string DEFAULT_DIR = self::ASC_DIR;
public function __construct(public string|null $field = null, public string $direction = self::DEFAULT_DIR)
{

View File

@@ -17,14 +17,14 @@ use function Shlinkio\Shlink\Core\enumValues;
/** @extends InputFilter<mixed> */
class RedirectRulesInputFilter extends InputFilter
{
public const REDIRECT_RULES = 'redirectRules';
public const string REDIRECT_RULES = 'redirectRules';
public const RULE_LONG_URL = 'longUrl';
public const RULE_CONDITIONS = 'conditions';
public const string RULE_LONG_URL = 'longUrl';
public const string RULE_CONDITIONS = 'conditions';
public const CONDITION_TYPE = 'type';
public const CONDITION_MATCH_VALUE = 'matchValue';
public const CONDITION_MATCH_KEY = 'matchKey';
public const string CONDITION_TYPE = 'type';
public const string CONDITION_MATCH_VALUE = 'matchValue';
public const string CONDITION_MATCH_KEY = 'matchKey';
private function __construct()
{

View File

@@ -21,14 +21,14 @@ use function trim;
readonly class ShortUrlTitleResolutionHelper implements ShortUrlTitleResolutionHelperInterface
{
public const MAX_REDIRECTS = 15;
public const CHROME_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
public const int MAX_REDIRECTS = 15;
public const string CHROME_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
. 'Chrome/121.0.0.0 Safari/537.36';
// Matches the value inside a html title tag
private const TITLE_TAG_VALUE = '/<title[^>]*>(.*?)<\/title>/i';
private const string TITLE_TAG_VALUE = '/<title[^>]*>(.*?)<\/title>/i';
// Matches the charset inside a Content-Type header
private const CHARSET_VALUE = '/charset=([^;]+)/i';
private const string CHARSET_VALUE = '/charset=([^;]+)/i';
public function __construct(
private ClientInterface $httpClient,

View File

@@ -14,7 +14,7 @@ use function rtrim;
class TrimTrailingSlashMiddleware implements MiddlewareInterface
{
private const SHORT_CODE_ATTR = 'shortCode';
private const string SHORT_CODE_ATTR = 'shortCode';
public function __construct(private readonly UrlShortenerOptions $options)
{

View File

@@ -12,8 +12,8 @@ use function strpbrk;
class CustomSlugValidator extends AbstractValidator
{
private const NOT_STRING = 'NOT_STRING';
private const CONTAINS_URL_CHARACTERS = 'CONTAINS_URL_CHARACTERS';
private const string NOT_STRING = 'NOT_STRING';
private const string CONTAINS_URL_CHARACTERS = 'CONTAINS_URL_CHARACTERS';
protected array $messageTemplates = [
self::NOT_STRING => 'Provided value is not a string.',

View File

@@ -24,22 +24,22 @@ use const Shlinkio\Shlink\MIN_SHORT_CODES_LENGTH;
class ShortUrlInputFilter extends InputFilter
{
// Fields for creation only
public const SHORT_CODE_LENGTH = 'shortCodeLength';
public const CUSTOM_SLUG = 'customSlug';
public const PATH_PREFIX = 'pathPrefix';
public const FIND_IF_EXISTS = 'findIfExists';
public const DOMAIN = 'domain';
public const string SHORT_CODE_LENGTH = 'shortCodeLength';
public const string CUSTOM_SLUG = 'customSlug';
public const string PATH_PREFIX = 'pathPrefix';
public const string FIND_IF_EXISTS = 'findIfExists';
public const string DOMAIN = 'domain';
// Fields for creation and edition
public const LONG_URL = 'longUrl';
public const VALID_SINCE = 'validSince';
public const VALID_UNTIL = 'validUntil';
public const MAX_VISITS = 'maxVisits';
public const TITLE = 'title';
public const TAGS = 'tags';
public const CRAWLABLE = 'crawlable';
public const FORWARD_QUERY = 'forwardQuery';
public const API_KEY = 'apiKey';
public const string LONG_URL = 'longUrl';
public const string VALID_SINCE = 'validSince';
public const string VALID_UNTIL = 'validUntil';
public const string MAX_VISITS = 'maxVisits';
public const string TITLE = 'title';
public const string TAGS = 'tags';
public const string CRAWLABLE = 'crawlable';
public const string FORWARD_QUERY = 'forwardQuery';
public const string API_KEY = 'apiKey';
public static function forCreation(array $data, UrlShortenerOptions $options): self
{

View File

@@ -16,17 +16,17 @@ use function Shlinkio\Shlink\Core\enumValues;
/** @extends InputFilter<mixed> */
class ShortUrlsParamsInputFilter extends InputFilter
{
public const PAGE = 'page';
public const SEARCH_TERM = 'searchTerm';
public const TAGS = 'tags';
public const START_DATE = 'startDate';
public const END_DATE = 'endDate';
public const ITEMS_PER_PAGE = 'itemsPerPage';
public const TAGS_MODE = 'tagsMode';
public const ORDER_BY = 'orderBy';
public const EXCLUDE_MAX_VISITS_REACHED = 'excludeMaxVisitsReached';
public const EXCLUDE_PAST_VALID_UNTIL = 'excludePastValidUntil';
public const DOMAIN = 'domain';
public const string PAGE = 'page';
public const string SEARCH_TERM = 'searchTerm';
public const string TAGS = 'tags';
public const string START_DATE = 'startDate';
public const string END_DATE = 'endDate';
public const string ITEMS_PER_PAGE = 'itemsPerPage';
public const string TAGS_MODE = 'tagsMode';
public const string ORDER_BY = 'orderBy';
public const string EXCLUDE_MAX_VISITS_REACHED = 'excludeMaxVisitsReached';
public const string EXCLUDE_PAST_VALID_UNTIL = 'excludePastValidUntil';
public const string DOMAIN = 'domain';
public function __construct(array $data)
{

View File

@@ -17,11 +17,11 @@ use const Shlinkio\Shlink\REDIRECT_URL_REQUEST_ATTRIBUTE;
final readonly class Visitor
{
public const USER_AGENT_MAX_LENGTH = 512;
public const REFERER_MAX_LENGTH = 1024;
public const REMOTE_ADDRESS_MAX_LENGTH = 256;
public const VISITED_URL_MAX_LENGTH = 2048;
public const REDIRECT_URL_MAX_LENGTH = 2048;
public const int USER_AGENT_MAX_LENGTH = 512;
public const int REFERER_MAX_LENGTH = 1024;
public const int REMOTE_ADDRESS_MAX_LENGTH = 256;
public const int VISITED_URL_MAX_LENGTH = 2048;
public const int REDIRECT_URL_MAX_LENGTH = 2048;
private function __construct(
public string $userAgent,

View File

@@ -9,7 +9,7 @@ use Shlinkio\Shlink\Core\Visit\Entity\Visit;
interface VisitIterationRepositoryInterface
{
public const DEFAULT_BLOCK_SIZE = 10000;
public const int DEFAULT_BLOCK_SIZE = 10000;
/**
* @return iterable<Visit>

View File

@@ -32,8 +32,8 @@ use const Shlinkio\Shlink\DEFAULT_QR_CODE_COLOR;
class QrCodeActionTest extends TestCase
{
private const WHITE = 0xFFFFFF;
private const BLACK = 0x0;
private const int WHITE = 0xFFFFFF;
private const int BLACK = 0x0;
private MockObject & ShortUrlResolverInterface $urlResolver;

View File

@@ -23,7 +23,7 @@ use const Shlinkio\Shlink\REDIRECT_URL_REQUEST_ATTRIBUTE;
class RedirectActionTest extends TestCase
{
private const LONG_URL = 'https://domain.com/foo/bar?some=thing';
private const string LONG_URL = 'https://domain.com/foo/bar?some=thing';
private RedirectAction $action;
private MockObject & ShortUrlResolverInterface $urlResolver;

View File

@@ -22,7 +22,7 @@ use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
class ShortUrlTitleResolutionHelperTest extends TestCase
{
private const LONG_URL = 'http://foobar.com/12345/hello?foo=bar';
private const string LONG_URL = 'http://foobar.com/12345/hello?foo=bar';
private MockObject & ClientInterface $httpClient;

View File

@@ -23,7 +23,7 @@ use const Shlinkio\Shlink\IP_ADDRESS_REQUEST_ATTRIBUTE;
class RequestTrackerTest extends TestCase
{
private const LONG_URL = 'https://domain.com/foo/bar?some=thing';
private const string LONG_URL = 'https://domain.com/foo/bar?some=thing';
private RequestTracker $requestTracker;
private MockObject & VisitsTrackerInterface $visitsTracker;

View File

@@ -10,8 +10,8 @@ use Psr\Http\Server\RequestHandlerInterface;
abstract class AbstractRestAction implements RequestHandlerInterface, RequestMethodInterface, StatusCodeInterface
{
protected const ROUTE_PATH = '';
protected const ROUTE_ALLOWED_METHODS = [];
protected const string ROUTE_PATH = '';
protected const array ROUTE_ALLOWED_METHODS = [];
public static function getRouteDef(array $prevMiddleware = [], array $postMiddleware = []): array
{

View File

@@ -14,10 +14,10 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class DomainRedirectsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/domains/redirects';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH];
protected const string ROUTE_PATH = '/domains/redirects';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH];
public function __construct(private DomainServiceInterface $domainService)
public function __construct(private readonly DomainServiceInterface $domainService)
{
}

View File

@@ -15,11 +15,13 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class ListDomainsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/domains';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/domains';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private DomainServiceInterface $domainService, private NotFoundRedirectOptions $options)
{
public function __construct(
private readonly DomainServiceInterface $domainService,
private readonly NotFoundRedirectOptions $options,
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface

View File

@@ -13,14 +13,14 @@ use Throwable;
class HealthAction extends AbstractRestAction
{
private const HEALTH_CONTENT_TYPE = 'application/health+json';
private const STATUS_PASS = 'pass';
private const STATUS_FAIL = 'fail';
private const string HEALTH_CONTENT_TYPE = 'application/health+json';
private const string STATUS_PASS = 'pass';
private const string STATUS_FAIL = 'fail';
public const ROUTE_PATH = '/health';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public const string ROUTE_PATH = '/health';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private EntityManagerInterface $em, private AppOptions $options)
public function __construct(private readonly EntityManagerInterface $em, private readonly AppOptions $options)
{
}

View File

@@ -15,11 +15,13 @@ use function sprintf;
class MercureInfoAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/mercure-info';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/mercure-info';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private JwtProviderInterface $jwtProvider, private array $mercureConfig)
{
public function __construct(
private readonly JwtProviderInterface $jwtProvider,
private readonly array $mercureConfig,
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface

View File

@@ -13,8 +13,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class ListRedirectRulesAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}/redirect-rules';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/short-urls/{shortCode}/redirect-rules';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(
private readonly ShortUrlResolverInterface $urlResolver,

View File

@@ -16,8 +16,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class SetRedirectRulesAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}/redirect-rules';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST, self::METHOD_PATCH];
protected const string ROUTE_PATH = '/short-urls/{shortCode}/redirect-rules';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_POST, self::METHOD_PATCH];
public function __construct(
private readonly ShortUrlResolverInterface $urlResolver,

View File

@@ -12,8 +12,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class CreateShortUrlAction extends AbstractCreateShortUrlAction
{
protected const ROUTE_PATH = '/short-urls';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST];
protected const string ROUTE_PATH = '/short-urls';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_POST];
/**
* @throws ValidationException

View File

@@ -14,8 +14,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class DeleteShortUrlAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
protected const string ROUTE_PATH = '/short-urls/{shortCode}';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
public function __construct(private DeleteShortUrlServiceInterface $deleteShortUrlService)
{

View File

@@ -14,8 +14,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class DeleteShortUrlVisitsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}/visits';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
protected const string ROUTE_PATH = '/short-urls/{shortCode}/visits';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
public function __construct(private readonly ShortUrlVisitsDeleterInterface $deleter)
{

View File

@@ -16,8 +16,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class EditShortUrlAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH];
protected const string ROUTE_PATH = '/short-urls/{shortCode}';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH];
public function __construct(
private readonly ShortUrlServiceInterface $shortUrlService,

View File

@@ -16,8 +16,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class ListShortUrlsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/short-urls';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(
private readonly ShortUrlListServiceInterface $shortUrlService,

View File

@@ -15,8 +15,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class ResolveShortUrlAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/short-urls/{shortCode}';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(
private readonly ShortUrlResolverInterface $urlResolver,

View File

@@ -11,8 +11,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class SingleStepCreateShortUrlAction extends AbstractCreateShortUrlAction
{
protected const ROUTE_PATH = '/short-urls/shorten';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/short-urls/shorten';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected function buildShortUrlData(Request $request): ShortUrlCreation
{

View File

@@ -13,10 +13,10 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class DeleteTagsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/tags';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
protected const string ROUTE_PATH = '/tags';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
public function __construct(private TagServiceInterface $tagService)
public function __construct(private readonly TagServiceInterface $tagService)
{
}

View File

@@ -15,8 +15,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class ListTagsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/tags';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/tags';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private readonly TagServiceInterface $tagService)
{

View File

@@ -15,8 +15,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class TagsStatsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/tags/stats';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/tags/stats';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private readonly TagServiceInterface $tagService)
{

View File

@@ -14,10 +14,10 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class UpdateTagAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/tags';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
protected const string ROUTE_PATH = '/tags';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
public function __construct(private TagServiceInterface $tagService)
public function __construct(private readonly TagServiceInterface $tagService)
{
}

View File

@@ -18,7 +18,7 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
abstract class AbstractListVisitsAction extends AbstractRestAction
{
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(protected readonly VisitsStatsHelperInterface $visitsHelper)
{

View File

@@ -13,8 +13,8 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class DeleteOrphanVisitsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/visits/orphan';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
protected const string ROUTE_PATH = '/visits/orphan';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
public function __construct(private readonly VisitsDeleterInterface $visitsDeleter)
{

View File

@@ -14,7 +14,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class DomainVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/domains/{domain}/visits';
protected const string ROUTE_PATH = '/domains/{domain}/visits';
public function __construct(
VisitsStatsHelperInterface $visitsHelper,

View File

@@ -13,10 +13,10 @@ use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
class GlobalVisitsAction extends AbstractRestAction
{
protected const ROUTE_PATH = '/visits';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
protected const string ROUTE_PATH = '/visits';
protected const array ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
public function __construct(private VisitsStatsHelperInterface $statsHelper)
public function __construct(private readonly VisitsStatsHelperInterface $statsHelper)
{
}

View File

@@ -11,7 +11,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class NonOrphanVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/visits/non-orphan';
protected const string ROUTE_PATH = '/visits/non-orphan';
protected function getVisitsPaginator(
ServerRequestInterface $request,

View File

@@ -12,7 +12,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class OrphanVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/visits/orphan';
protected const string ROUTE_PATH = '/visits/orphan';
protected function getVisitsPaginator(
ServerRequestInterface $request,

View File

@@ -12,7 +12,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/short-urls/{shortCode}/visits';
protected const string ROUTE_PATH = '/short-urls/{shortCode}/visits';
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
{

View File

@@ -11,7 +11,7 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class TagVisitsAction extends AbstractListVisitsAction
{
protected const ROUTE_PATH = '/tags/{tag}/visits';
protected const string ROUTE_PATH = '/tags/{tag}/visits';
protected function getVisitsPaginator(Request $request, VisitsParams $params, ApiKey $apiKey): Pagerfanta
{

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