Migrated all constructor props to property promotion when possible

This commit is contained in:
Alejandro Celaya 2021-05-23 11:57:31 +02:00
parent 4b5fa6ddad
commit e0f0bb5523
118 changed files with 237 additions and 713 deletions

View File

@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -63,7 +63,7 @@ jobs:
- run: composer install --no-interaction --prefer-dist - run: composer install --no-interaction --prefer-dist
- run: composer test:unit:ci - run: composer test:unit:ci
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
if: ${{ matrix.php-version == '7.4' }} if: ${{ matrix.php-version == '8.0' }}
with: with:
name: coverage-unit name: coverage-unit
path: | path: |
@ -74,7 +74,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -89,7 +89,7 @@ jobs:
- run: composer install --no-interaction --prefer-dist - run: composer install --no-interaction --prefer-dist
- run: composer test:db:sqlite:ci - run: composer test:db:sqlite:ci
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
if: ${{ matrix.php-version == '7.4' }} if: ${{ matrix.php-version == '8.0' }}
with: with:
name: coverage-db name: coverage-db
path: | path: |
@ -100,7 +100,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -120,7 +120,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -140,7 +140,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -160,7 +160,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -184,7 +184,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -201,7 +201,7 @@ jobs:
- run: composer install --no-interaction --prefer-dist - run: composer install --no-interaction --prefer-dist
- run: bin/test/run-api-tests.sh - run: bin/test/run-api-tests.sh
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
if: ${{ matrix.php-version == '7.4' }} if: ${{ matrix.php-version == '8.0' }}
with: with:
name: coverage-api name: coverage-api
path: | path: |
@ -216,7 +216,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
test-group: ['unit', 'db'] test-group: ['unit', 'db']
steps: steps:
- name: Checkout code - name: Checkout code

View File

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: ['7.4', '8.0'] php-version: ['8.0']
swoole: ['yes', 'no'] swoole: ['yes', 'no']
steps: steps:
- name: Checkout code - name: Checkout code
@ -54,7 +54,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
php-version: [ '7.4', '8.0' ] php-version: [ '8.0' ]
swoole: [ 'yes', 'no' ] swoole: [ 'yes', 'no' ]
steps: steps:
- uses: geekyeggo/delete-artifact@v1 - uses: geekyeggo/delete-artifact@v1

View File

@ -33,7 +33,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: First, make sure the host where you are going to run shlink fulfills these requirements:
* PHP 7.4 or 8.0 * PHP 8.0
* The next PHP extensions: json, curl, pdo, intl, gd and gmp. * The next PHP extensions: json, curl, pdo, intl, gd and gmp.
* apcu extension is recommended if you don't plan to use swoole. * apcu extension is recommended if you don't plan to use swoole.
* xml extension is required if you want to generate QR codes in svg format. * xml extension is required if you want to generate QR codes in svg format.

View File

@ -12,7 +12,7 @@
} }
], ],
"require": { "require": {
"php": "^7.4 || ^8.0", "php": "^8.0",
"ext-json": "*", "ext-json": "*",
"ext-pdo": "*", "ext-pdo": "*",
"akrabat/ip-address-middleware": "^2.0", "akrabat/ip-address-middleware": "^2.0",

View File

@ -11,7 +11,7 @@ server {
location ~ \.php$ { location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_index index.php; fastcgi_index index.php;
include fastcgi.conf; include fastcgi.conf;
} }

View File

@ -10,11 +10,8 @@ use Symfony\Component\Console\Input\InputInterface;
class RoleResolver implements RoleResolverInterface class RoleResolver implements RoleResolverInterface
{ {
private DomainServiceInterface $domainService; public function __construct(private DomainServiceInterface $domainService)
public function __construct(DomainServiceInterface $domainService)
{ {
$this->domainService = $domainService;
} }
public function determineRoles(InputInterface $input): array public function determineRoles(InputInterface $input): array

View File

@ -19,12 +19,9 @@ class DisableKeyCommand extends Command
{ {
public const NAME = 'api-key:disable'; public const NAME = 'api-key:disable';
private ApiKeyServiceInterface $apiKeyService; public function __construct(private ApiKeyServiceInterface $apiKeyService)
public function __construct(ApiKeyServiceInterface $apiKeyService)
{ {
parent::__construct(); parent::__construct();
$this->apiKeyService = $apiKeyService;
} }
protected function configure(): void protected function configure(): void

View File

@ -23,14 +23,11 @@ class GenerateKeyCommand extends BaseCommand
{ {
public const NAME = 'api-key:generate'; public const NAME = 'api-key:generate';
private ApiKeyServiceInterface $apiKeyService; public function __construct(
private RoleResolverInterface $roleResolver; private ApiKeyServiceInterface $apiKeyService,
private RoleResolverInterface $roleResolver
public function __construct(ApiKeyServiceInterface $apiKeyService, RoleResolverInterface $roleResolver) ) {
{
parent::__construct(); parent::__construct();
$this->apiKeyService = $apiKeyService;
$this->roleResolver = $roleResolver;
} }
protected function configure(): void protected function configure(): void

View File

@ -27,12 +27,9 @@ class ListKeysCommand extends BaseCommand
public const NAME = 'api-key:list'; public const NAME = 'api-key:list';
private ApiKeyServiceInterface $apiKeyService; public function __construct(private ApiKeyServiceInterface $apiKeyService)
public function __construct(ApiKeyServiceInterface $apiKeyService)
{ {
parent::__construct(); parent::__construct();
$this->apiKeyService = $apiKeyService;
} }
protected function configure(): void protected function configure(): void

View File

@ -13,16 +13,14 @@ use Symfony\Component\Process\PhpExecutableFinder;
abstract class AbstractDatabaseCommand extends AbstractLockedCommand abstract class AbstractDatabaseCommand extends AbstractLockedCommand
{ {
private ProcessRunnerInterface $processRunner;
private string $phpBinary; private string $phpBinary;
public function __construct( public function __construct(
LockFactory $locker, LockFactory $locker,
ProcessRunnerInterface $processRunner, private ProcessRunnerInterface $processRunner,
PhpExecutableFinder $phpFinder PhpExecutableFinder $phpFinder
) { ) {
parent::__construct($locker); parent::__construct($locker);
$this->processRunner = $processRunner;
$this->phpBinary = $phpFinder->find(false) ?: 'php'; $this->phpBinary = $phpFinder->find(false) ?: 'php';
} }

View File

@ -21,19 +21,14 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
public const DOCTRINE_SCRIPT = 'vendor/doctrine/orm/bin/doctrine.php'; public const DOCTRINE_SCRIPT = 'vendor/doctrine/orm/bin/doctrine.php';
public const DOCTRINE_CREATE_SCHEMA_COMMAND = 'orm:schema-tool:create'; public const DOCTRINE_CREATE_SCHEMA_COMMAND = 'orm:schema-tool:create';
private Connection $regularConn;
private Connection $noDbNameConn;
public function __construct( public function __construct(
LockFactory $locker, LockFactory $locker,
ProcessRunnerInterface $processRunner, ProcessRunnerInterface $processRunner,
PhpExecutableFinder $phpFinder, PhpExecutableFinder $phpFinder,
Connection $conn, private Connection $regularConn,
Connection $noDbNameConn private Connection $noDbNameConn
) { ) {
parent::__construct($locker, $processRunner, $phpFinder); parent::__construct($locker, $processRunner, $phpFinder);
$this->regularConn = $conn;
$this->noDbNameConn = $noDbNameConn;
} }
protected function configure(): void protected function configure(): void

View File

@ -18,12 +18,9 @@ class ListDomainsCommand extends Command
{ {
public const NAME = 'domain:list'; public const NAME = 'domain:list';
private DomainServiceInterface $domainService; public function __construct(private DomainServiceInterface $domainService)
public function __construct(DomainServiceInterface $domainService)
{ {
parent::__construct(); parent::__construct();
$this->domainService = $domainService;
} }
protected function configure(): void protected function configure(): void

View File

@ -21,12 +21,9 @@ class DeleteShortUrlCommand extends Command
{ {
public const NAME = 'short-url:delete'; public const NAME = 'short-url:delete';
private DeleteShortUrlServiceInterface $deleteShortUrlService; public function __construct(private DeleteShortUrlServiceInterface $deleteShortUrlService)
public function __construct(DeleteShortUrlServiceInterface $deleteShortUrlService)
{ {
parent::__construct(); parent::__construct();
$this->deleteShortUrlService = $deleteShortUrlService;
} }
protected function configure(): void protected function configure(): void

View File

@ -30,19 +30,12 @@ class GenerateShortUrlCommand extends BaseCommand
{ {
public const NAME = 'short-url:generate'; public const NAME = 'short-url:generate';
private UrlShortenerInterface $urlShortener;
private ShortUrlStringifierInterface $stringifier;
private int $defaultShortCodeLength;
public function __construct( public function __construct(
UrlShortenerInterface $urlShortener, private UrlShortenerInterface $urlShortener,
ShortUrlStringifierInterface $stringifier, private ShortUrlStringifierInterface $stringifier,
int $defaultShortCodeLength private int $defaultShortCodeLength
) { ) {
parent::__construct(); parent::__construct();
$this->urlShortener = $urlShortener;
$this->stringifier = $stringifier;
$this->defaultShortCodeLength = $defaultShortCodeLength;
} }
protected function configure(): void protected function configure(): void

View File

@ -27,11 +27,8 @@ class GetVisitsCommand extends AbstractWithDateRangeCommand
{ {
public const NAME = 'short-url:visits'; public const NAME = 'short-url:visits';
private VisitsStatsHelperInterface $visitsHelper; public function __construct(private VisitsStatsHelperInterface $visitsHelper)
public function __construct(VisitsStatsHelperInterface $visitsHelper)
{ {
$this->visitsHelper = $visitsHelper;
parent::__construct(); parent::__construct();
} }

View File

@ -33,14 +33,11 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand
public const NAME = 'short-url:list'; public const NAME = 'short-url:list';
private ShortUrlServiceInterface $shortUrlService; public function __construct(
private DataTransformerInterface $transformer; private ShortUrlServiceInterface $shortUrlService,
private DataTransformerInterface $transformer
public function __construct(ShortUrlServiceInterface $shortUrlService, DataTransformerInterface $transformer) ) {
{
parent::__construct(); parent::__construct();
$this->shortUrlService = $shortUrlService;
$this->transformer = $transformer;
} }
protected function doConfigure(): void protected function doConfigure(): void

View File

@ -21,12 +21,9 @@ class ResolveUrlCommand extends Command
{ {
public const NAME = 'short-url:parse'; public const NAME = 'short-url:parse';
private ShortUrlResolverInterface $urlResolver; public function __construct(private ShortUrlResolverInterface $urlResolver)
public function __construct(ShortUrlResolverInterface $urlResolver)
{ {
parent::__construct(); parent::__construct();
$this->urlResolver = $urlResolver;
} }
protected function configure(): void protected function configure(): void

View File

@ -17,12 +17,9 @@ class CreateTagCommand extends Command
{ {
public const NAME = 'tag:create'; public const NAME = 'tag:create';
private TagServiceInterface $tagService; public function __construct(private TagServiceInterface $tagService)
public function __construct(TagServiceInterface $tagService)
{ {
parent::__construct(); parent::__construct();
$this->tagService = $tagService;
} }
protected function configure(): void protected function configure(): void

View File

@ -16,12 +16,9 @@ class DeleteTagsCommand extends Command
{ {
public const NAME = 'tag:delete'; public const NAME = 'tag:delete';
private TagServiceInterface $tagService; public function __construct(private TagServiceInterface $tagService)
public function __construct(TagServiceInterface $tagService)
{ {
parent::__construct(); parent::__construct();
$this->tagService = $tagService;
} }
protected function configure(): void protected function configure(): void

View File

@ -18,12 +18,9 @@ class ListTagsCommand extends Command
{ {
public const NAME = 'tag:list'; public const NAME = 'tag:list';
private TagServiceInterface $tagService; public function __construct(private TagServiceInterface $tagService)
public function __construct(TagServiceInterface $tagService)
{ {
parent::__construct(); parent::__construct();
$this->tagService = $tagService;
} }
protected function configure(): void protected function configure(): void

View File

@ -19,12 +19,9 @@ class RenameTagCommand extends Command
{ {
public const NAME = 'tag:rename'; public const NAME = 'tag:rename';
private TagServiceInterface $tagService; public function __construct(private TagServiceInterface $tagService)
public function __construct(TagServiceInterface $tagService)
{ {
parent::__construct(); parent::__construct();
$this->tagService = $tagService;
} }
protected function configure(): void protected function configure(): void

View File

@ -14,12 +14,9 @@ use function sprintf;
abstract class AbstractLockedCommand extends Command abstract class AbstractLockedCommand extends Command
{ {
private LockFactory $locker; public function __construct(private LockFactory $locker)
public function __construct(LockFactory $locker)
{ {
parent::__construct(); parent::__construct();
$this->locker = $locker;
} }
final protected function execute(InputInterface $input, OutputInterface $output): ?int final protected function execute(InputInterface $input, OutputInterface $output): ?int

View File

@ -8,15 +8,11 @@ final class LockedCommandConfig
{ {
public const DEFAULT_TTL = 600.0; // 10 minutes public const DEFAULT_TTL = 600.0; // 10 minutes
private string $lockName; private function __construct(
private bool $isBlocking; private string $lockName,
private float $ttl; private bool $isBlocking,
private float $ttl = self::DEFAULT_TTL
private function __construct(string $lockName, bool $isBlocking, float $ttl = self::DEFAULT_TTL) ) {
{
$this->lockName = $lockName;
$this->isBlocking = $isBlocking;
$this->ttl = $ttl;
} }
public static function blocking(string $lockName): self public static function blocking(string $lockName): self

View File

@ -19,13 +19,11 @@ class DownloadGeoLiteDbCommand extends Command
{ {
public const NAME = 'visit:download-db'; public const NAME = 'visit:download-db';
private GeolocationDbUpdaterInterface $dbUpdater;
private ?ProgressBar $progressBar = null; private ?ProgressBar $progressBar = null;
public function __construct(GeolocationDbUpdaterInterface $dbUpdater) public function __construct(private GeolocationDbUpdaterInterface $dbUpdater)
{ {
parent::__construct(); parent::__construct();
$this->dbUpdater = $dbUpdater;
} }
protected function configure(): void protected function configure(): void

View File

@ -30,19 +30,14 @@ class LocateVisitsCommand extends AbstractLockedCommand implements VisitGeolocat
{ {
public const NAME = 'visit:locate'; public const NAME = 'visit:locate';
private VisitLocatorInterface $visitLocator;
private IpLocationResolverInterface $ipLocationResolver;
private SymfonyStyle $io; private SymfonyStyle $io;
public function __construct( public function __construct(
VisitLocatorInterface $visitLocator, private VisitLocatorInterface $visitLocator,
IpLocationResolverInterface $ipLocationResolver, private IpLocationResolverInterface $ipLocationResolver,
LockFactory $locker LockFactory $locker
) { ) {
parent::__construct($locker); parent::__construct($locker);
$this->visitLocator = $visitLocator;
$this->ipLocationResolver = $ipLocationResolver;
} }
protected function configure(): void protected function configure(): void

View File

@ -18,15 +18,11 @@ class GeolocationDbUpdater implements GeolocationDbUpdaterInterface
{ {
private const LOCK_NAME = 'geolocation-db-update'; private const LOCK_NAME = 'geolocation-db-update';
private DbUpdaterInterface $dbUpdater; public function __construct(
private Reader $geoLiteDbReader; private DbUpdaterInterface $dbUpdater,
private LockFactory $locker; private Reader $geoLiteDbReader,
private LockFactory $locker
public function __construct(DbUpdaterInterface $dbUpdater, Reader $geoLiteDbReader, LockFactory $locker) ) {
{
$this->dbUpdater = $dbUpdater;
$this->geoLiteDbReader = $geoLiteDbReader;
$this->locker = $locker;
} }
/** /**

View File

@ -18,12 +18,10 @@ use function str_replace;
class ProcessRunner implements ProcessRunnerInterface class ProcessRunner implements ProcessRunnerInterface
{ {
private ProcessHelper $helper;
private Closure $createProcess; private Closure $createProcess;
public function __construct(ProcessHelper $helper, ?callable $createProcess = null) public function __construct(private ProcessHelper $helper, ?callable $createProcess = null)
{ {
$this->helper = $helper;
$this->createProcess = $createProcess !== null $this->createProcess = $createProcess !== null
? Closure::fromCallable($createProcess) ? Closure::fromCallable($createProcess)
: static fn (array $cmd) => new Process($cmd, null, null, null, LockedCommandConfig::DEFAULT_TTL); : static fn (array $cmd) => new Process($cmd, null, null, null, LockedCommandConfig::DEFAULT_TTL);

View File

@ -12,11 +12,8 @@ final class ShlinkTable
private const DEFAULT_STYLE_NAME = 'default'; private const DEFAULT_STYLE_NAME = 'default';
private const TABLE_TITLE_STYLE = '<options=bold> %s </>'; private const TABLE_TITLE_STYLE = '<options=bold> %s </>';
private ?Table $baseTable; public function __construct(private Table $baseTable)
public function __construct(Table $baseTable)
{ {
$this->baseTable = $baseTable;
} }
public static function fromOutput(OutputInterface $output): self public static function fromOutput(OutputInterface $output): self

View File

@ -51,20 +51,12 @@ function parseDateRangeFromQuery(array $query, string $startDateName, string $en
$startDate = parseDateFromQuery($query, $startDateName); $startDate = parseDateFromQuery($query, $startDateName);
$endDate = parseDateFromQuery($query, $endDateName); $endDate = parseDateFromQuery($query, $endDateName);
// TODO Use match expression when migrating to PHP8 return match (true) {
if ($startDate === null && $endDate === null) { $startDate === null && $endDate === null => DateRange::emptyInstance(),
return DateRange::emptyInstance(); $startDate !== null && $endDate !== null => DateRange::withStartAndEndDate($startDate, $endDate),
} $startDate !== null => DateRange::withStartDate($startDate),
default => DateRange::withEndDate($endDate),
if ($startDate !== null && $endDate !== null) { };
return DateRange::withStartAndEndDate($startDate, $endDate);
}
if ($startDate !== null) {
return DateRange::withStartDate($startDate);
}
return DateRange::withEndDate($endDate);
} }
/** /**

View File

@ -27,20 +27,14 @@ use function array_merge;
abstract class AbstractTrackingAction implements MiddlewareInterface, RequestMethodInterface abstract class AbstractTrackingAction implements MiddlewareInterface, RequestMethodInterface
{ {
private ShortUrlResolverInterface $urlResolver;
private VisitsTrackerInterface $visitTracker;
private TrackingOptions $trackingOptions;
private LoggerInterface $logger; private LoggerInterface $logger;
public function __construct( public function __construct(
ShortUrlResolverInterface $urlResolver, private ShortUrlResolverInterface $urlResolver,
VisitsTrackerInterface $visitTracker, private VisitsTrackerInterface $visitTracker,
TrackingOptions $trackingOptions, private TrackingOptions $trackingOptions,
?LoggerInterface $logger = null ?LoggerInterface $logger = null
) { ) {
$this->urlResolver = $urlResolver;
$this->visitTracker = $visitTracker;
$this->trackingOptions = $trackingOptions;
$this->logger = $logger ?? new NullLogger(); $this->logger = $logger ?? new NullLogger();
} }

View File

@ -24,18 +24,14 @@ class QrCodeAction implements MiddlewareInterface
private const MIN_SIZE = 50; private const MIN_SIZE = 50;
private const MAX_SIZE = 1000; private const MAX_SIZE = 1000;
private ShortUrlResolverInterface $urlResolver;
private ShortUrlStringifierInterface $stringifier;
private LoggerInterface $logger; private LoggerInterface $logger;
public function __construct( public function __construct(
ShortUrlResolverInterface $urlResolver, private ShortUrlResolverInterface $urlResolver,
ShortUrlStringifierInterface $stringifier, private ShortUrlStringifierInterface $stringifier,
?LoggerInterface $logger = null ?LoggerInterface $logger = null
) { ) {
$this->urlResolver = $urlResolver;
$this->logger = $logger ?? new NullLogger(); $this->logger = $logger ?? new NullLogger();
$this->stringifier = $stringifier;
} }
public function process(Request $request, RequestHandlerInterface $handler): Response public function process(Request $request, RequestHandlerInterface $handler): Response

View File

@ -16,17 +16,14 @@ use Shlinkio\Shlink\Core\Visit\VisitsTrackerInterface;
class RedirectAction extends AbstractTrackingAction implements StatusCodeInterface class RedirectAction extends AbstractTrackingAction implements StatusCodeInterface
{ {
private RedirectResponseHelperInterface $redirectResponseHelper;
public function __construct( public function __construct(
ShortUrlResolverInterface $urlResolver, ShortUrlResolverInterface $urlResolver,
VisitsTrackerInterface $visitTracker, VisitsTrackerInterface $visitTracker,
Options\TrackingOptions $trackingOptions, Options\TrackingOptions $trackingOptions,
RedirectResponseHelperInterface $redirectResponseHelper, private RedirectResponseHelperInterface $redirectResponseHelper,
?LoggerInterface $logger = null ?LoggerInterface $logger = null
) { ) {
parent::__construct($urlResolver, $visitTracker, $trackingOptions, $logger); parent::__construct($urlResolver, $visitTracker, $trackingOptions, $logger);
$this->redirectResponseHelper = $redirectResponseHelper;
} }
protected function createSuccessResp(string $longUrl): Response protected function createSuccessResp(string $longUrl): Response

View File

@ -17,11 +17,8 @@ use const PHP_EOL;
class RobotsAction implements RequestHandlerInterface, StatusCodeInterface class RobotsAction implements RequestHandlerInterface, StatusCodeInterface
{ {
private CrawlingHelperInterface $crawlingHelper; public function __construct(private CrawlingHelperInterface $crawlingHelper)
public function __construct(CrawlingHelperInterface $crawlingHelper)
{ {
$this->crawlingHelper = $crawlingHelper;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -10,11 +10,8 @@ use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
class CrawlingHelper implements CrawlingHelperInterface class CrawlingHelper implements CrawlingHelperInterface
{ {
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em)
{ {
$this->em = $em;
} }
public function listCrawlableShortCodes(): iterable public function listCrawlableShortCodes(): iterable

View File

@ -16,13 +16,8 @@ use function Functional\map;
class DomainService implements DomainServiceInterface class DomainService implements DomainServiceInterface
{ {
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em, private string $defaultDomain)
private string $defaultDomain;
public function __construct(EntityManagerInterface $em, string $defaultDomain)
{ {
$this->em = $em;
$this->defaultDomain = $defaultDomain;
} }
/** /**

View File

@ -8,13 +8,8 @@ use JsonSerializable;
final class DomainItem implements JsonSerializable final class DomainItem implements JsonSerializable
{ {
private string $domain; public function __construct(private string $domain, private bool $isDefault)
private bool $isDefault;
public function __construct(string $domain, bool $isDefault)
{ {
$this->domain = $domain;
$this->isDefault = $isDefault;
} }
public function jsonSerialize(): array public function jsonSerialize(): array

View File

@ -9,11 +9,8 @@ use Shlinkio\Shlink\Common\Entity\AbstractEntity;
class Domain extends AbstractEntity implements JsonSerializable class Domain extends AbstractEntity implements JsonSerializable
{ {
private string $authority; public function __construct(private string $authority)
public function __construct(string $authority)
{ {
$this->authority = $authority;
} }
public function getAuthority(): string public function getAuthority(): string

View File

@ -10,12 +10,10 @@ use Shlinkio\Shlink\Common\Entity\AbstractEntity;
class Tag extends AbstractEntity implements JsonSerializable class Tag extends AbstractEntity implements JsonSerializable
{ {
private string $name;
private Collections\Collection $shortUrls; private Collections\Collection $shortUrls;
public function __construct(string $name) public function __construct(private string $name)
{ {
$this->name = $name;
$this->shortUrls = new Collections\ArrayCollection(); $this->shortUrls = new Collections\ArrayCollection();
} }

View File

@ -13,31 +13,24 @@ use function rtrim;
class NotFoundType class NotFoundType
{ {
private string $type; private function __construct(private string $type)
private function __construct(string $type)
{ {
$this->type = $type;
} }
public static function fromRequest(ServerRequestInterface $request, string $basePath): self public static function fromRequest(ServerRequestInterface $request, string $basePath): self
{ {
$isBaseUrl = rtrim($request->getUri()->getPath(), '/') === $basePath;
if ($isBaseUrl) {
return new self(Visit::TYPE_BASE_URL);
}
/** @var RouteResult $routeResult */ /** @var RouteResult $routeResult */
$routeResult = $request->getAttribute(RouteResult::class, RouteResult::fromRouteFailure(null)); $routeResult = $request->getAttribute(RouteResult::class, RouteResult::fromRouteFailure(null));
if ($routeResult->isFailure()) { $isBaseUrl = rtrim($request->getUri()->getPath(), '/') === $basePath;
return new self(Visit::TYPE_REGULAR_404);
}
if ($routeResult->getMatchedRouteName() === RedirectAction::class) { $type = match (true) {
return new self(Visit::TYPE_INVALID_SHORT_URL); $isBaseUrl => Visit::TYPE_BASE_URL,
} $routeResult->isFailure() => Visit::TYPE_REGULAR_404,
$routeResult->getMatchedRouteName() === RedirectAction::class => Visit::TYPE_INVALID_SHORT_URL,
default => self::class,
};
return new self(self::class); return new self($type);
} }
public function isBaseUrl(): bool public function isBaseUrl(): bool

View File

@ -14,15 +14,10 @@ use Shlinkio\Shlink\Core\Util\RedirectResponseHelperInterface;
class NotFoundRedirectHandler implements MiddlewareInterface class NotFoundRedirectHandler implements MiddlewareInterface
{ {
private Options\NotFoundRedirectOptions $redirectOptions;
private RedirectResponseHelperInterface $redirectResponseHelper;
public function __construct( public function __construct(
Options\NotFoundRedirectOptions $redirectOptions, private Options\NotFoundRedirectOptions $redirectOptions,
RedirectResponseHelperInterface $redirectResponseHelper private RedirectResponseHelperInterface $redirectResponseHelper
) { ) {
$this->redirectOptions = $redirectOptions;
$this->redirectResponseHelper = $redirectResponseHelper;
} }
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface

View File

@ -20,6 +20,7 @@ class NotFoundTemplateHandler implements RequestHandlerInterface
private const TEMPLATES_BASE_DIR = __DIR__ . '/../../templates'; private const TEMPLATES_BASE_DIR = __DIR__ . '/../../templates';
public const NOT_FOUND_TEMPLATE = '404.html'; public const NOT_FOUND_TEMPLATE = '404.html';
public const INVALID_SHORT_CODE_TEMPLATE = 'invalid-short-code.html'; public const INVALID_SHORT_CODE_TEMPLATE = 'invalid-short-code.html';
private Closure $readFile; private Closure $readFile;
public function __construct(?callable $readFile = null) public function __construct(?callable $readFile = null)

View File

@ -14,11 +14,8 @@ use Shlinkio\Shlink\Core\Visit\VisitsTrackerInterface;
class NotFoundTrackerMiddleware implements MiddlewareInterface class NotFoundTrackerMiddleware implements MiddlewareInterface
{ {
private VisitsTrackerInterface $visitsTracker; public function __construct(private VisitsTrackerInterface $visitsTracker)
public function __construct(VisitsTrackerInterface $visitsTracker)
{ {
$this->visitsTracker = $visitsTracker;
} }
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface

View File

@ -12,11 +12,8 @@ use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType;
class NotFoundTypeResolverMiddleware implements MiddlewareInterface class NotFoundTypeResolverMiddleware implements MiddlewareInterface
{ {
private string $shlinkBasePath; public function __construct(private string $shlinkBasePath)
public function __construct(string $shlinkBasePath)
{ {
$this->shlinkBasePath = $shlinkBasePath;
} }
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface

View File

@ -8,13 +8,11 @@ use Shlinkio\Shlink\Common\Doctrine\ReopeningEntityManagerInterface;
class CloseDbConnectionEventListener class CloseDbConnectionEventListener
{ {
private ReopeningEntityManagerInterface $em;
/** @var callable */ /** @var callable */
private $wrapped; private $wrapped;
public function __construct(ReopeningEntityManagerInterface $em, callable $wrapped) public function __construct(private ReopeningEntityManagerInterface $em, callable $wrapped)
{ {
$this->em = $em;
$this->wrapped = $wrapped; $this->wrapped = $wrapped;
} }

View File

@ -8,11 +8,8 @@ use JsonSerializable;
abstract class AbstractVisitEvent implements JsonSerializable abstract class AbstractVisitEvent implements JsonSerializable
{ {
protected string $visitId; public function __construct(protected string $visitId)
public function __construct(string $visitId)
{ {
$this->visitId = $visitId;
} }
public function visitId(): string public function visitId(): string

View File

@ -6,12 +6,9 @@ namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
final class UrlVisited extends AbstractVisitEvent final class UrlVisited extends AbstractVisitEvent
{ {
private ?string $originalIpAddress; public function __construct(string $visitId, private ?string $originalIpAddress = null)
public function __construct(string $visitId, ?string $originalIpAddress = null)
{ {
parent::__construct($visitId); parent::__construct($visitId);
$this->originalIpAddress = $originalIpAddress;
} }
public function originalIpAddress(): ?string public function originalIpAddress(): ?string

View File

@ -19,24 +19,13 @@ use Throwable;
class LocateVisit class LocateVisit
{ {
private IpLocationResolverInterface $ipLocationResolver;
private EntityManagerInterface $em;
private LoggerInterface $logger;
private DbUpdaterInterface $dbUpdater;
private EventDispatcherInterface $eventDispatcher;
public function __construct( public function __construct(
IpLocationResolverInterface $ipLocationResolver, private IpLocationResolverInterface $ipLocationResolver,
EntityManagerInterface $em, private EntityManagerInterface $em,
LoggerInterface $logger, private LoggerInterface $logger,
DbUpdaterInterface $dbUpdater, private DbUpdaterInterface $dbUpdater,
EventDispatcherInterface $eventDispatcher private EventDispatcherInterface $eventDispatcher
) { ) {
$this->ipLocationResolver = $ipLocationResolver;
$this->em = $em;
$this->logger = $logger;
$this->dbUpdater = $dbUpdater;
$this->eventDispatcher = $eventDispatcher;
} }
public function __invoke(UrlVisited $shortUrlVisited): void public function __invoke(UrlVisited $shortUrlVisited): void

View File

@ -17,21 +17,12 @@ use function Functional\each;
class NotifyVisitToMercure class NotifyVisitToMercure
{ {
private HubInterface $hub;
private MercureUpdatesGeneratorInterface $updatesGenerator;
private EntityManagerInterface $em;
private LoggerInterface $logger;
public function __construct( public function __construct(
HubInterface $hub, private HubInterface $hub,
MercureUpdatesGeneratorInterface $updatesGenerator, private MercureUpdatesGeneratorInterface $updatesGenerator,
EntityManagerInterface $em, private EntityManagerInterface $em,
LoggerInterface $logger private LoggerInterface $logger
) { ) {
$this->hub = $hub;
$this->em = $em;
$this->logger = $logger;
$this->updatesGenerator = $updatesGenerator;
} }
public function __invoke(VisitLocated $shortUrlLocated): void public function __invoke(VisitLocated $shortUrlLocated): void

View File

@ -24,28 +24,15 @@ use function Functional\partial_left;
class NotifyVisitToWebHooks class NotifyVisitToWebHooks
{ {
private ClientInterface $httpClient;
private EntityManagerInterface $em;
private LoggerInterface $logger;
/** @var string[] */
private array $webhooks;
private DataTransformerInterface $transformer;
private AppOptions $appOptions;
public function __construct( public function __construct(
ClientInterface $httpClient, private ClientInterface $httpClient,
EntityManagerInterface $em, private EntityManagerInterface $em,
LoggerInterface $logger, private LoggerInterface $logger,
array $webhooks, /** @var string[] */
DataTransformerInterface $transformer, private array $webhooks,
AppOptions $appOptions private DataTransformerInterface $transformer,
private AppOptions $appOptions
) { ) {
$this->httpClient = $httpClient;
$this->em = $em;
$this->logger = $logger;
$this->webhooks = $webhooks;
$this->transformer = $transformer;
$this->appOptions = $appOptions;
} }
public function __invoke(VisitLocated $shortUrlLocated): void public function __invoke(VisitLocated $shortUrlLocated): void

View File

@ -12,13 +12,8 @@ use function sprintf;
class UpdateGeoLiteDb class UpdateGeoLiteDb
{ {
private GeolocationDbUpdaterInterface $dbUpdater; public function __construct(private GeolocationDbUpdaterInterface $dbUpdater, private LoggerInterface $logger)
private LoggerInterface $logger;
public function __construct(GeolocationDbUpdaterInterface $dbUpdater, LoggerInterface $logger)
{ {
$this->dbUpdater = $dbUpdater;
$this->logger = $logger;
} }
public function __invoke(): void public function __invoke(): void

View File

@ -20,22 +20,14 @@ use function sprintf;
class ImportedLinksProcessor implements ImportedLinksProcessorInterface class ImportedLinksProcessor implements ImportedLinksProcessorInterface
{ {
private EntityManagerInterface $em;
private ShortUrlRelationResolverInterface $relationResolver;
private ShortCodeHelperInterface $shortCodeHelper;
private DoctrineBatchHelperInterface $batchHelper;
private ShortUrlRepositoryInterface $shortUrlRepo; private ShortUrlRepositoryInterface $shortUrlRepo;
public function __construct( public function __construct(
EntityManagerInterface $em, private EntityManagerInterface $em,
ShortUrlRelationResolverInterface $relationResolver, private ShortUrlRelationResolverInterface $relationResolver,
ShortCodeHelperInterface $shortCodeHelper, private ShortCodeHelperInterface $shortCodeHelper,
DoctrineBatchHelperInterface $batchHelper private DoctrineBatchHelperInterface $batchHelper
) { ) {
$this->em = $em;
$this->relationResolver = $relationResolver;
$this->shortCodeHelper = $shortCodeHelper;
$this->batchHelper = $batchHelper;
$this->shortUrlRepo = $this->em->getRepository(ShortUrl::class); // @phpstan-ignore-line $this->shortUrlRepo = $this->em->getRepository(ShortUrl::class); // @phpstan-ignore-line
} }
@ -64,7 +56,7 @@ class ImportedLinksProcessor implements ImportedLinksProcessorInterface
try { try {
$shortUrlImporting = $this->resolveShortUrl($importedUrl, $importShortCodes, $skipOnShortCodeConflict); $shortUrlImporting = $this->resolveShortUrl($importedUrl, $importShortCodes, $skipOnShortCodeConflict);
} catch (NonUniqueSlugException $e) { } catch (NonUniqueSlugException) {
$io->text(sprintf('%s: <fg=red>Error</>', $longUrl)); $io->text(sprintf('%s: <fg=red>Error</>', $longUrl));
continue; continue;
} }

View File

@ -14,13 +14,8 @@ use function sprintf;
final class ShortUrlImporting final class ShortUrlImporting
{ {
private ShortUrl $shortUrl; private function __construct(private ShortUrl $shortUrl, private bool $isNew)
private bool $isNew;
private function __construct(ShortUrl $shortUrl, bool $isNew)
{ {
$this->shortUrl = $shortUrl;
$this->isNew = $isNew;
} }
public static function fromExistingShortUrl(ShortUrl $shortUrl): self public static function fromExistingShortUrl(ShortUrl $shortUrl): self

View File

@ -18,15 +18,10 @@ final class MercureUpdatesGenerator implements MercureUpdatesGeneratorInterface
private const NEW_VISIT_TOPIC = 'https://shlink.io/new-visit'; private const NEW_VISIT_TOPIC = 'https://shlink.io/new-visit';
private const NEW_ORPHAN_VISIT_TOPIC = 'https://shlink.io/new-orphan-visit'; private const NEW_ORPHAN_VISIT_TOPIC = 'https://shlink.io/new-orphan-visit';
private DataTransformerInterface $shortUrlTransformer;
private DataTransformerInterface $orphanVisitTransformer;
public function __construct( public function __construct(
DataTransformerInterface $shortUrlTransformer, private DataTransformerInterface $shortUrlTransformer,
DataTransformerInterface $orphanVisitTransformer private DataTransformerInterface $orphanVisitTransformer
) { ) {
$this->shortUrlTransformer = $shortUrlTransformer;
$this->orphanVisitTransformer = $orphanVisitTransformer;
} }
public function newVisitUpdate(Visit $visit): Update public function newVisitUpdate(Visit $visit): Update

View File

@ -10,13 +10,8 @@ use Symfony\Component\Console\Input\InputInterface;
final class ShortUrlIdentifier final class ShortUrlIdentifier
{ {
private string $shortCode; public function __construct(private string $shortCode, private ?string $domain = null)
private ?string $domain;
public function __construct(string $shortCode, ?string $domain = null)
{ {
$this->shortCode = $shortCode;
$this->domain = $domain;
} }
public static function fromApiRequest(ServerRequestInterface $request): self public static function fromApiRequest(ServerRequestInterface $request): self

View File

@ -14,20 +14,16 @@ final class VisitsParams
private const ALL_ITEMS = -1; private const ALL_ITEMS = -1;
private ?DateRange $dateRange; private ?DateRange $dateRange;
private int $page;
private int $itemsPerPage; private int $itemsPerPage;
private bool $excludeBots;
public function __construct( public function __construct(
?DateRange $dateRange = null, ?DateRange $dateRange = null,
int $page = self::FIRST_PAGE, private int $page = self::FIRST_PAGE,
?int $itemsPerPage = null, ?int $itemsPerPage = null,
bool $excludeBots = false private bool $excludeBots = false
) { ) {
$this->dateRange = $dateRange ?? new DateRange(); $this->dateRange = $dateRange ?? new DateRange();
$this->page = $page;
$this->itemsPerPage = $this->determineItemsPerPage($itemsPerPage); $this->itemsPerPage = $this->determineItemsPerPage($itemsPerPage);
$this->excludeBots = $excludeBots;
} }
private function determineItemsPerPage(?int $itemsPerPage): int private function determineItemsPerPage(?int $itemsPerPage): int

View File

@ -11,13 +11,8 @@ use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter class OrphanVisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
{ {
private VisitRepositoryInterface $repo; public function __construct(private VisitRepositoryInterface $repo, private VisitsParams $params)
private VisitsParams $params;
public function __construct(VisitRepositoryInterface $repo, VisitsParams $params)
{ {
$this->repo = $repo;
$this->params = $params;
} }
protected function doCount(): int protected function doCount(): int

View File

@ -12,15 +12,11 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlRepositoryAdapter implements AdapterInterface class ShortUrlRepositoryAdapter implements AdapterInterface
{ {
private ShortUrlRepositoryInterface $repository; public function __construct(
private ShortUrlsParams $params; private ShortUrlRepositoryInterface $repository,
private ?ApiKey $apiKey; private ShortUrlsParams $params,
private ?ApiKey $apiKey
public function __construct(ShortUrlRepositoryInterface $repository, ShortUrlsParams $params, ?ApiKey $apiKey) ) {
{
$this->repository = $repository;
$this->params = $params;
$this->apiKey = $apiKey;
} }
public function getSlice($offset, $length): array // phpcs:ignore public function getSlice($offset, $length): array // phpcs:ignore

View File

@ -13,21 +13,12 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class VisitsForTagPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter class VisitsForTagPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
{ {
private VisitRepositoryInterface $visitRepository;
private string $tag;
private VisitsParams $params;
private ?ApiKey $apiKey;
public function __construct( public function __construct(
VisitRepositoryInterface $visitRepository, private VisitRepositoryInterface $visitRepository,
string $tag, private string $tag,
VisitsParams $params, private VisitsParams $params,
?ApiKey $apiKey private ?ApiKey $apiKey
) { ) {
$this->visitRepository = $visitRepository;
$this->params = $params;
$this->tag = $tag;
$this->apiKey = $apiKey;
} }
public function getSlice($offset, $length): array // phpcs:ignore public function getSlice($offset, $length): array // phpcs:ignore

View File

@ -13,21 +13,12 @@ use Shlinkio\Shlink\Core\Visit\Persistence\VisitsListFiltering;
class VisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter class VisitsPaginatorAdapter extends AbstractCacheableCountPaginatorAdapter
{ {
private VisitRepositoryInterface $visitRepository;
private ShortUrlIdentifier $identifier;
private VisitsParams $params;
private ?Specification $spec;
public function __construct( public function __construct(
VisitRepositoryInterface $visitRepository, private VisitRepositoryInterface $visitRepository,
ShortUrlIdentifier $identifier, private ShortUrlIdentifier $identifier,
VisitsParams $params, private VisitsParams $params,
?Specification $spec private ?Specification $spec
) { ) {
$this->visitRepository = $visitRepository;
$this->params = $params;
$this->identifier = $identifier;
$this->spec = $spec;
} }
public function getSlice($offset, $length): array // phpcs:ignore public function getSlice($offset, $length): array // phpcs:ignore

View File

@ -13,18 +13,11 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class DeleteShortUrlService implements DeleteShortUrlServiceInterface class DeleteShortUrlService implements DeleteShortUrlServiceInterface
{ {
private EntityManagerInterface $em;
private DeleteShortUrlsOptions $deleteShortUrlsOptions;
private ShortUrlResolverInterface $urlResolver;
public function __construct( public function __construct(
EntityManagerInterface $em, private EntityManagerInterface $em,
DeleteShortUrlsOptions $deleteShortUrlsOptions, private DeleteShortUrlsOptions $deleteShortUrlsOptions,
ShortUrlResolverInterface $urlResolver private ShortUrlResolverInterface $urlResolver
) { ) {
$this->em = $em;
$this->deleteShortUrlsOptions = $deleteShortUrlsOptions;
$this->urlResolver = $urlResolver;
} }
/** /**

View File

@ -11,11 +11,8 @@ use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
class ShortCodeHelper implements ShortCodeHelperInterface // TODO Rename to ShortCodeUniquenessHelper class ShortCodeHelper implements ShortCodeHelperInterface // TODO Rename to ShortCodeUniquenessHelper
{ {
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em)
{ {
$this->em = $em;
} }
public function ensureShortCodeUniqueness(ShortUrl $shortUrlToBeCreated, bool $hasCustomSlug): bool public function ensureShortCodeUniqueness(ShortUrl $shortUrlToBeCreated, bool $hasCustomSlug): bool

View File

@ -13,11 +13,8 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlResolver implements ShortUrlResolverInterface class ShortUrlResolver implements ShortUrlResolverInterface
{ {
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em)
{ {
$this->em = $em;
} }
/** /**

View File

@ -21,21 +21,12 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ShortUrlService implements ShortUrlServiceInterface class ShortUrlService implements ShortUrlServiceInterface
{ {
private ORM\EntityManagerInterface $em;
private ShortUrlResolverInterface $urlResolver;
private ShortUrlTitleResolutionHelperInterface $titleResolutionHelper;
private ShortUrlRelationResolverInterface $relationResolver;
public function __construct( public function __construct(
ORM\EntityManagerInterface $em, private ORM\EntityManagerInterface $em,
ShortUrlResolverInterface $urlResolver, private ShortUrlResolverInterface $urlResolver,
ShortUrlTitleResolutionHelperInterface $titleResolutionHelper, private ShortUrlTitleResolutionHelperInterface $titleResolutionHelper,
ShortUrlRelationResolverInterface $relationResolver private ShortUrlRelationResolverInterface $relationResolver
) { ) {
$this->em = $em;
$this->urlResolver = $urlResolver;
$this->titleResolutionHelper = $titleResolutionHelper;
$this->relationResolver = $relationResolver;
} }
/** /**

View File

@ -16,21 +16,12 @@ use Shlinkio\Shlink\Core\ShortUrl\Resolver\ShortUrlRelationResolverInterface;
class UrlShortener implements UrlShortenerInterface class UrlShortener implements UrlShortenerInterface
{ {
private EntityManagerInterface $em;
private ShortUrlTitleResolutionHelperInterface $titleResolutionHelper;
private ShortUrlRelationResolverInterface $relationResolver;
private ShortCodeHelperInterface $shortCodeHelper;
public function __construct( public function __construct(
ShortUrlTitleResolutionHelperInterface $titleResolutionHelper, private ShortUrlTitleResolutionHelperInterface $titleResolutionHelper,
EntityManagerInterface $em, private EntityManagerInterface $em,
ShortUrlRelationResolverInterface $relationResolver, private ShortUrlRelationResolverInterface $relationResolver,
ShortCodeHelperInterface $shortCodeHelper private ShortCodeHelperInterface $shortCodeHelper
) { ) {
$this->titleResolutionHelper = $titleResolutionHelper;
$this->em = $em;
$this->relationResolver = $relationResolver;
$this->shortCodeHelper = $shortCodeHelper;
} }
/** /**

View File

@ -11,13 +11,8 @@ use function sprintf;
class ShortUrlStringifier implements ShortUrlStringifierInterface class ShortUrlStringifier implements ShortUrlStringifierInterface
{ {
private array $domainConfig; public function __construct(private array $domainConfig, private string $basePath = '')
private string $basePath;
public function __construct(array $domainConfig, string $basePath = '')
{ {
$this->domainConfig = $domainConfig;
$this->basePath = $basePath;
} }
public function stringify(ShortUrl $shortUrl): string public function stringify(ShortUrl $shortUrl): string

View File

@ -8,11 +8,8 @@ use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
class ShortUrlTitleResolutionHelper implements ShortUrlTitleResolutionHelperInterface class ShortUrlTitleResolutionHelper implements ShortUrlTitleResolutionHelperInterface
{ {
private UrlValidatorInterface $urlValidator; public function __construct(private UrlValidatorInterface $urlValidator)
public function __construct(UrlValidatorInterface $urlValidator)
{ {
$this->urlValidator = $urlValidator;
} }
public function processTitleAndValidateUrl(TitleResolutionModelInterface $data): TitleResolutionModelInterface public function processTitleAndValidateUrl(TitleResolutionModelInterface $data): TitleResolutionModelInterface

View File

@ -16,16 +16,13 @@ use function Functional\unique;
class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInterface class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInterface
{ {
private EntityManagerInterface $em;
/** @var array<string, Domain> */ /** @var array<string, Domain> */
private array $memoizedNewDomains = []; private array $memoizedNewDomains = [];
/** @var array<string, Tag> */ /** @var array<string, Tag> */
private array $memoizedNewTags = []; private array $memoizedNewTags = [];
public function __construct(EntityManagerInterface $em) public function __construct(private EntityManagerInterface $em)
{ {
$this->em = $em;
$this->em->getEventManager()->addEventListener(Events::postFlush, $this); $this->em->getEventManager()->addEventListener(Events::postFlush, $this);
} }

View File

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

View File

@ -10,11 +10,8 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class BelongsToApiKeyInlined implements Filter class BelongsToApiKeyInlined implements Filter
{ {
private ApiKey $apiKey; public function __construct(private ApiKey $apiKey)
public function __construct(ApiKey $apiKey)
{ {
$this->apiKey = $apiKey;
} }
public function getFilter(QueryBuilder $qb, string $dqlAlias): string public function getFilter(QueryBuilder $qb, string $dqlAlias): string

View File

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

View File

@ -9,11 +9,8 @@ use Happyr\DoctrineSpecification\Filter\Filter;
class BelongsToDomainInlined implements Filter class BelongsToDomainInlined implements Filter
{ {
private string $domainId; public function __construct(private string $domainId)
public function __construct(string $domainId)
{ {
$this->domainId = $domainId;
} }
public function getFilter(QueryBuilder $qb, string $dqlAlias): string public function getFilter(QueryBuilder $qb, string $dqlAlias): string

View File

@ -13,11 +13,8 @@ use function Functional\invoke_if;
class ShortUrlDataTransformer implements DataTransformerInterface class ShortUrlDataTransformer implements DataTransformerInterface
{ {
private ShortUrlStringifierInterface $stringifier; public function __construct(private ShortUrlStringifierInterface $stringifier)
public function __construct(ShortUrlStringifierInterface $stringifier)
{ {
$this->stringifier = $stringifier;
} }
/** /**

View File

@ -11,14 +11,9 @@ use Shlinkio\Shlink\Common\Util\DateRange;
class InDateRange extends BaseSpecification class InDateRange extends BaseSpecification
{ {
private ?DateRange $dateRange; public function __construct(private ?DateRange $dateRange, private string $field = 'date')
private string $field;
public function __construct(?DateRange $dateRange, string $field = 'date')
{ {
parent::__construct(); parent::__construct();
$this->dateRange = $dateRange;
$this->field = $field;
} }
protected function getSpec(): Specification protected function getSpec(): Specification

View File

@ -9,15 +9,8 @@ use Shlinkio\Shlink\Core\Entity\Tag;
final class TagInfo implements JsonSerializable final class TagInfo implements JsonSerializable
{ {
private Tag $tag; public function __construct(private Tag $tag, private int $shortUrlsCount, private int $visitsCount)
private int $shortUrlsCount;
private int $visitsCount;
public function __construct(Tag $tag, int $shortUrlsCount, int $visitsCount)
{ {
$this->tag = $tag;
$this->shortUrlsCount = $shortUrlsCount;
$this->visitsCount = $visitsCount;
} }
public function tag(): Tag public function tag(): Tag

View File

@ -10,12 +10,9 @@ use Happyr\DoctrineSpecification\Specification\Specification;
class CountTagsWithName extends BaseSpecification class CountTagsWithName extends BaseSpecification
{ {
private string $tagName; public function __construct(private string $tagName)
public function __construct(string $tagName)
{ {
parent::__construct(); parent::__construct();
$this->tagName = $tagName;
} }
protected function getSpec(): Specification protected function getSpec(): Specification

View File

@ -23,11 +23,8 @@ class TagService implements TagServiceInterface
{ {
use TagManagerTrait; use TagManagerTrait;
private ORM\EntityManagerInterface $em; public function __construct(private ORM\EntityManagerInterface $em)
public function __construct(ORM\EntityManagerInterface $em)
{ {
$this->em = $em;
} }
/** /**

View File

@ -12,11 +12,8 @@ use function Symfony\Component\String\s;
class CocurSymfonySluggerBridge implements SluggerInterface class CocurSymfonySluggerBridge implements SluggerInterface
{ {
private SlugifyInterface $slugger; public function __construct(private SlugifyInterface $slugger)
public function __construct(SlugifyInterface $slugger)
{ {
$this->slugger = $slugger;
} }
public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString public function slug(string $string, string $separator = '-', ?string $locale = null): AbstractUnicodeString

View File

@ -12,11 +12,8 @@ use Throwable;
*/ */
class DoctrineBatchHelper implements DoctrineBatchHelperInterface class DoctrineBatchHelper implements DoctrineBatchHelperInterface
{ {
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em)
{ {
$this->em = $em;
} }
/** /**

View File

@ -13,11 +13,8 @@ use function sprintf;
class RedirectResponseHelper implements RedirectResponseHelperInterface class RedirectResponseHelper implements RedirectResponseHelperInterface
{ {
private UrlShortenerOptions $options; public function __construct(private UrlShortenerOptions $options)
public function __construct(UrlShortenerOptions $options)
{ {
$this->options = $options;
} }
public function buildRedirectResponse(string $location): ResponseInterface public function buildRedirectResponse(string $location): ResponseInterface

View File

@ -23,13 +23,8 @@ class UrlValidator implements UrlValidatorInterface, RequestMethodInterface
private const CHROME_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' private const CHROME_USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
. 'Chrome/51.0.2704.103 Safari/537.36'; . 'Chrome/51.0.2704.103 Safari/537.36';
private ClientInterface $httpClient; public function __construct(private ClientInterface $httpClient, private UrlShortenerOptions $options)
private UrlShortenerOptions $options;
public function __construct(ClientInterface $httpClient, UrlShortenerOptions $options)
{ {
$this->httpClient = $httpClient;
$this->options = $options;
} }
/** /**

View File

@ -8,13 +8,8 @@ use JsonSerializable;
final class VisitsStats implements JsonSerializable final class VisitsStats implements JsonSerializable
{ {
private int $visitsCount; public function __construct(private int $visitsCount, private int $orphanVisitsCount)
private int $orphanVisitsCount;
public function __construct(int $visitsCount, int $orphanVisitsCount)
{ {
$this->visitsCount = $visitsCount;
$this->orphanVisitsCount = $orphanVisitsCount;
} }
public function jsonSerialize(): array public function jsonSerialize(): array

View File

@ -9,15 +9,11 @@ use Shlinkio\Shlink\Common\Util\DateRange;
class VisitsCountFiltering class VisitsCountFiltering
{ {
private ?DateRange $dateRange; public function __construct(
private bool $excludeBots; private ?DateRange $dateRange = null,
private ?Specification $spec; private bool $excludeBots = false,
private ?Specification $spec = null
public function __construct(?DateRange $dateRange = null, bool $excludeBots = false, ?Specification $spec = null) ) {
{
$this->dateRange = $dateRange;
$this->excludeBots = $excludeBots;
$this->spec = $spec;
} }
public function dateRange(): ?DateRange public function dateRange(): ?DateRange

View File

@ -9,19 +9,14 @@ use Shlinkio\Shlink\Common\Util\DateRange;
final class VisitsListFiltering extends VisitsCountFiltering final class VisitsListFiltering extends VisitsCountFiltering
{ {
private ?int $limit;
private ?int $offset;
public function __construct( public function __construct(
?DateRange $dateRange = null, ?DateRange $dateRange = null,
bool $excludeBots = false, bool $excludeBots = false,
?Specification $spec = null, ?Specification $spec = null,
?int $limit = null, private ?int $limit = null,
?int $offset = null private ?int $offset = null
) { ) {
parent::__construct($dateRange, $excludeBots, $spec); parent::__construct($dateRange, $excludeBots, $spec);
$this->limit = $limit;
$this->offset = $offset;
} }
public function limit(): ?int public function limit(): ?int

View File

@ -12,12 +12,9 @@ use Shlinkio\Shlink\Core\Visit\Persistence\VisitsCountFiltering;
class CountOfOrphanVisits extends BaseSpecification class CountOfOrphanVisits extends BaseSpecification
{ {
private VisitsCountFiltering $filtering; public function __construct(private VisitsCountFiltering $filtering)
public function __construct(VisitsCountFiltering $filtering)
{ {
parent::__construct(); parent::__construct();
$this->filtering = $filtering;
} }
protected function getSpec(): Specification protected function getSpec(): Specification

View File

@ -12,12 +12,9 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class CountOfShortUrlVisits extends BaseSpecification class CountOfShortUrlVisits extends BaseSpecification
{ {
private ?ApiKey $apiKey; public function __construct(private ?ApiKey $apiKey)
public function __construct(?ApiKey $apiKey)
{ {
parent::__construct(); parent::__construct();
$this->apiKey = $apiKey;
} }
protected function getSpec(): Specification protected function getSpec(): Specification

View File

@ -13,13 +13,10 @@ use Shlinkio\Shlink\IpGeolocation\Model\Location;
class VisitLocator implements VisitLocatorInterface class VisitLocator implements VisitLocatorInterface
{ {
private EntityManagerInterface $em;
private VisitRepositoryInterface $repo; private VisitRepositoryInterface $repo;
public function __construct(EntityManagerInterface $em) public function __construct(private EntityManagerInterface $em)
{ {
$this->em = $em;
/** @var VisitRepositoryInterface $repo */ /** @var VisitRepositoryInterface $repo */
$repo = $em->getRepository(Visit::class); $repo = $em->getRepository(Visit::class);
$this->repo = $repo; $this->repo = $repo;

View File

@ -27,11 +27,8 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class VisitsStatsHelper implements VisitsStatsHelperInterface class VisitsStatsHelper implements VisitsStatsHelperInterface
{ {
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em)
{ {
$this->em = $em;
} }
public function getVisitsStats(?ApiKey $apiKey = null): VisitsStats public function getVisitsStats(?ApiKey $apiKey = null): VisitsStats

View File

@ -14,18 +14,11 @@ use Shlinkio\Shlink\Core\Options\TrackingOptions;
class VisitsTracker implements VisitsTrackerInterface class VisitsTracker implements VisitsTrackerInterface
{ {
private ORM\EntityManagerInterface $em;
private EventDispatcherInterface $eventDispatcher;
private TrackingOptions $options;
public function __construct( public function __construct(
ORM\EntityManagerInterface $em, private ORM\EntityManagerInterface $em,
EventDispatcherInterface $eventDispatcher, private EventDispatcherInterface $eventDispatcher,
TrackingOptions $options private TrackingOptions $options
) { ) {
$this->em = $em;
$this->eventDispatcher = $eventDispatcher;
$this->options = $options;
} }
public function track(ShortUrl $shortUrl, Visitor $visitor): void public function track(ShortUrl $shortUrl, Visitor $visitor): void

View File

@ -94,11 +94,8 @@ class DomainRepositoryTest extends DatabaseTestCase
return ShortUrl::fromMeta( return ShortUrl::fromMeta(
ShortUrlMeta::fromRawData(['domain' => $domain->getAuthority(), 'apiKey' => $apiKey, 'longUrl' => 'foo']), ShortUrlMeta::fromRawData(['domain' => $domain->getAuthority(), 'apiKey' => $apiKey, 'longUrl' => 'foo']),
new class ($domain) implements ShortUrlRelationResolverInterface { new class ($domain) implements ShortUrlRelationResolverInterface {
private Domain $domain; public function __construct(private Domain $domain)
public function __construct(Domain $domain)
{ {
$this->domain = $domain;
} }
public function resolveDomain(?string $domain): ?Domain public function resolveDomain(?string $domain): ?Domain

View File

@ -122,11 +122,8 @@ class VisitLocatorTest extends TestCase
$this->visitService->{$serviceMethodName}( $this->visitService->{$serviceMethodName}(
new class ($isNonLocatableAddress) implements VisitGeolocationHelperInterface { new class ($isNonLocatableAddress) implements VisitGeolocationHelperInterface {
private bool $isNonLocatableAddress; public function __construct(private bool $isNonLocatableAddress)
public function __construct(bool $isNonLocatableAddress)
{ {
$this->isNonLocatableAddress = $isNonLocatableAddress;
} }
public function geolocateVisit(Visit $visit): Location public function geolocateVisit(Visit $visit): Location

View File

@ -16,11 +16,8 @@ class ListDomainsAction extends AbstractRestAction
protected const ROUTE_PATH = '/domains'; protected const ROUTE_PATH = '/domains';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
private DomainServiceInterface $domainService; public function __construct(private DomainServiceInterface $domainService)
public function __construct(DomainServiceInterface $domainService)
{ {
$this->domainService = $domainService;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -20,13 +20,8 @@ class HealthAction extends AbstractRestAction
protected const ROUTE_PATH = '/health'; protected const ROUTE_PATH = '/health';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
private EntityManagerInterface $em; public function __construct(private EntityManagerInterface $em, private AppOptions $options)
private AppOptions $options;
public function __construct(EntityManagerInterface $em, AppOptions $options)
{ {
$this->em = $em;
$this->options = $options;
} }
/** /**
@ -38,7 +33,7 @@ class HealthAction extends AbstractRestAction
{ {
try { try {
$connected = $this->em->getConnection()->ping(); $connected = $this->em->getConnection()->ping();
} catch (Throwable $e) { } catch (Throwable) {
$connected = false; $connected = false;
} }

View File

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

View File

@ -15,13 +15,10 @@ use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
abstract class AbstractCreateShortUrlAction extends AbstractRestAction abstract class AbstractCreateShortUrlAction extends AbstractRestAction
{ {
private UrlShortenerInterface $urlShortener; public function __construct(
private DataTransformerInterface $transformer; private UrlShortenerInterface $urlShortener,
private DataTransformerInterface $transformer,
public function __construct(UrlShortenerInterface $urlShortener, DataTransformerInterface $transformer) ) {
{
$this->urlShortener = $urlShortener;
$this->transformer = $transformer;
} }
public function handle(Request $request): Response public function handle(Request $request): Response

View File

@ -17,11 +17,8 @@ class DeleteShortUrlAction extends AbstractRestAction
protected const ROUTE_PATH = '/short-urls/{shortCode}'; protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_DELETE];
private DeleteShortUrlServiceInterface $deleteShortUrlService; public function __construct(private DeleteShortUrlServiceInterface $deleteShortUrlService)
public function __construct(DeleteShortUrlServiceInterface $deleteShortUrlService)
{ {
$this->deleteShortUrlService = $deleteShortUrlService;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -19,13 +19,10 @@ class EditShortUrlAction extends AbstractRestAction
protected const ROUTE_PATH = '/short-urls/{shortCode}'; protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH, self::METHOD_PUT]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PATCH, self::METHOD_PUT];
private ShortUrlServiceInterface $shortUrlService; public function __construct(
private DataTransformerInterface $transformer; private ShortUrlServiceInterface $shortUrlService,
private DataTransformerInterface $transformer,
public function __construct(ShortUrlServiceInterface $shortUrlService, DataTransformerInterface $transformer) ) {
{
$this->shortUrlService = $shortUrlService;
$this->transformer = $transformer;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -21,11 +21,8 @@ class EditShortUrlTagsAction extends AbstractRestAction
protected const ROUTE_PATH = '/short-urls/{shortCode}/tags'; protected const ROUTE_PATH = '/short-urls/{shortCode}/tags';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_PUT];
private ShortUrlServiceInterface $shortUrlService; public function __construct(private ShortUrlServiceInterface $shortUrlService)
public function __construct(ShortUrlServiceInterface $shortUrlService)
{ {
$this->shortUrlService = $shortUrlService;
} }
public function handle(Request $request): Response public function handle(Request $request): Response

View File

@ -21,13 +21,10 @@ class ListShortUrlsAction extends AbstractRestAction
protected const ROUTE_PATH = '/short-urls'; protected const ROUTE_PATH = '/short-urls';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
private ShortUrlServiceInterface $shortUrlService; public function __construct(
private DataTransformerInterface $transformer; private ShortUrlServiceInterface $shortUrlService,
private DataTransformerInterface $transformer
public function __construct(ShortUrlServiceInterface $shortUrlService, DataTransformerInterface $transformer) ) {
{
$this->shortUrlService = $shortUrlService;
$this->transformer = $transformer;
} }
public function handle(Request $request): Response public function handle(Request $request): Response

View File

@ -18,13 +18,10 @@ class ResolveShortUrlAction extends AbstractRestAction
protected const ROUTE_PATH = '/short-urls/{shortCode}'; protected const ROUTE_PATH = '/short-urls/{shortCode}';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_GET];
private ShortUrlResolverInterface $urlResolver; public function __construct(
private DataTransformerInterface $transformer; private ShortUrlResolverInterface $urlResolver,
private DataTransformerInterface $transformer,
public function __construct(ShortUrlResolverInterface $urlResolver, DataTransformerInterface $transformer) ) {
{
$this->urlResolver = $urlResolver;
$this->transformer = $transformer;
} }
public function handle(Request $request): Response public function handle(Request $request): Response

View File

@ -16,11 +16,8 @@ class CreateTagsAction extends AbstractRestAction
protected const ROUTE_PATH = '/tags'; protected const ROUTE_PATH = '/tags';
protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST]; protected const ROUTE_ALLOWED_METHODS = [self::METHOD_POST];
private TagServiceInterface $tagService; public function __construct(private TagServiceInterface $tagService)
public function __construct(TagServiceInterface $tagService)
{ {
$this->tagService = $tagService;
} }
/** /**

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