Skip to content

Commit 8df6fff

Browse files
authored
Merge pull request #260 from shlinkio/develop
Release 10.0.0
2 parents c61a11c + 2d76805 commit 8df6fff

File tree

50 files changed

+407
-1190
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+407
-1190
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
66

7+
## [10.0.0] - 2026-02-08
8+
### Added
9+
* Add support for Symfony 8.0
10+
11+
### Changed
12+
* Update to PHPUnit 13
13+
14+
### Deprecated
15+
* *Nothing*
16+
17+
### Removed
18+
* Remove QR code config options that were deprecated.
19+
* Remove append extra path config option that was deprecated.
20+
* Drop support for PHP 8.3.
21+
* Drop support for Symfony 7.x.
22+
23+
### Fixed
24+
* *Nothing*
25+
26+
727
## [9.7.0] - 2025-11-01
828
### Added
929
* Add `REDIS_SERVERS_USER` and `REDIS_SERVERS_PASSWORD` config options.

composer.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@
1212
}
1313
],
1414
"require": {
15-
"php": "^8.3",
16-
"laminas/laminas-config-aggregator": "^1.18",
17-
"laminas/laminas-servicemanager": "^4.4 || ^3.23",
18-
"laminas/laminas-stdlib": "^3.20",
15+
"php": "^8.4",
16+
"laminas/laminas-config-aggregator": "^1.19",
17+
"laminas/laminas-servicemanager": "^4.5 || ^3.24",
18+
"laminas/laminas-stdlib": "^3.21",
1919
"shlinkio/shlink-config": "^4.0",
20-
"symfony/console": "^7.3",
21-
"symfony/filesystem": "^7.3",
22-
"symfony/process": "^7.3",
20+
"symfony/console": "^8.0",
21+
"symfony/filesystem": "^8.0",
22+
"symfony/process": "^8.0",
2323
"webimpress/safe-writer": "^2.2"
2424
},
2525
"require-dev": {
2626
"devster/ubench": "^2.1",
2727
"phpstan/phpstan": "^2.1",
2828
"phpstan/phpstan-phpunit": "^2.0",
29-
"phpunit/phpunit": "^12.4",
29+
"phpunit/phpunit": "^13.0",
3030
"roave/security-advisories": "dev-master",
3131
"shlinkio/php-coding-standard": "~2.5.0",
32-
"symfony/var-dumper": "^7.3"
32+
"symfony/var-dumper": "^8.0"
3333
},
3434
"autoload": {
3535
"psr-4": {

config/config.php

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
Console\Helper\ProcessHelper::class => Factory\ProcessHelperFactory::class,
2424

2525
Service\InstallationCommandsRunner::class => ConfigAbstractFactory::class,
26+
Service\InstallationRunner::class => ConfigAbstractFactory::class,
2627
Service\ShlinkAssetsHandler::class => ConfigAbstractFactory::class,
2728
Config\ConfigGenerator::class => ConfigAbstractFactory::class,
2829
Config\ConfigOptionsManager::class => Config\ConfigOptionsManagerFactory::class,
@@ -61,7 +62,6 @@
6162
'URL shortener > Short codes length' => Config\Option\UrlShortener\ShortCodeLengthOption::class,
6263
'URL shortener > Auto resolve titles'
6364
=> Config\Option\UrlShortener\AutoResolveTitlesConfigOption::class,
64-
'URL shortener > Append extra path' => Config\Option\UrlShortener\AppendExtraPathConfigOption::class,
6565
'URL shortener > Extra path mode' => Config\Option\UrlShortener\ExtraPathModeConfigOption::class,
6666
'URL shortener > Multi-segment slugs'
6767
=> Config\Option\UrlShortener\EnableMultiSegmentSlugsConfigOption::class,
@@ -90,18 +90,6 @@
9090
'Redirects > Invalid short URL' => Config\Option\Redirect\InvalidShortUrlRedirectConfigOption::class,
9191
'Redirects > Regular 404' => Config\Option\Redirect\Regular404RedirectConfigOption::class,
9292
],
93-
'QR CODES [DEPRECATED]' => [
94-
'QR codes > Default size' => Config\Option\QrCode\DefaultSizeConfigOption::class,
95-
'QR codes > Default margin' => Config\Option\QrCode\DefaultMarginConfigOption::class,
96-
'QR codes > Default format' => Config\Option\QrCode\DefaultFormatConfigOption::class,
97-
'QR codes > Default error correction' => Config\Option\QrCode\DefaultErrorCorrectionConfigOption::class,
98-
'QR codes > Default round block size' => Config\Option\QrCode\DefaultRoundBlockSizeConfigOption::class,
99-
'QR codes > Default color' => Config\Option\QrCode\DefaultColorConfigOption::class,
100-
'QR codes > Default background color' => Config\Option\QrCode\DefaultBgColorConfigOption::class,
101-
'QR codes > Default logo URL' => Config\Option\QrCode\DefaultLogoUrlConfigOption::class,
102-
'QR codes > Enabled for disabled short URLs'
103-
=> Config\Option\QrCode\EnabledForDisabledShortUrlsConfigOption::class,
104-
],
10593
'ROBOTS' => [
10694
'Robots.txt > allow all' => Config\Option\Robots\RobotsAllowAllShortUrlsConfigOption::class,
10795
'Robots.txt > user agents' => Config\Option\Robots\RobotsUserAgentsConfigOption::class,
@@ -165,7 +153,6 @@
165153
Config\Option\UrlShortener\ShortDomainHostConfigOption::class => InvokableFactory::class,
166154
Config\Option\UrlShortener\ShortDomainSchemaConfigOption::class => InvokableFactory::class,
167155
Config\Option\UrlShortener\AutoResolveTitlesConfigOption::class => InvokableFactory::class,
168-
Config\Option\UrlShortener\AppendExtraPathConfigOption::class => InvokableFactory::class,
169156
Config\Option\UrlShortener\ExtraPathModeConfigOption::class => InvokableFactory::class,
170157
Config\Option\UrlShortener\EnableMultiSegmentSlugsConfigOption::class => InvokableFactory::class,
171158
Config\Option\UrlShortener\EnableTrailingSlashConfigOption::class => InvokableFactory::class,
@@ -208,15 +195,6 @@
208195
Config\Option\Cors\CorsAllowOriginConfigOption::class => InvokableFactory::class,
209196
Config\Option\Cors\CorsAllowCredentialsConfigOption::class => InvokableFactory::class,
210197
Config\Option\Cors\CorsMaxAgeConfigOption::class => InvokableFactory::class,
211-
Config\Option\QrCode\DefaultSizeConfigOption::class => InvokableFactory::class,
212-
Config\Option\QrCode\DefaultMarginConfigOption::class => InvokableFactory::class,
213-
Config\Option\QrCode\DefaultFormatConfigOption::class => InvokableFactory::class,
214-
Config\Option\QrCode\DefaultErrorCorrectionConfigOption::class => InvokableFactory::class,
215-
Config\Option\QrCode\DefaultRoundBlockSizeConfigOption::class => InvokableFactory::class,
216-
Config\Option\QrCode\DefaultColorConfigOption::class => InvokableFactory::class,
217-
Config\Option\QrCode\DefaultBgColorConfigOption::class => InvokableFactory::class,
218-
Config\Option\QrCode\DefaultLogoUrlConfigOption::class => InvokableFactory::class,
219-
Config\Option\QrCode\EnabledForDisabledShortUrlsConfigOption::class => InvokableFactory::class,
220198
],
221199
],
222200

@@ -232,17 +210,14 @@
232210
PhpExecutableFinder::class,
233211
'config.installer.installation_commands',
234212
],
235-
236-
Command\InstallCommand::class => [
237-
ConfigWriter::class,
238-
Service\ShlinkAssetsHandler::class,
239-
Config\ConfigGenerator::class,
240-
],
241-
Command\UpdateCommand::class => [
213+
Service\InstallationRunner::class => [
242214
ConfigWriter::class,
243215
Service\ShlinkAssetsHandler::class,
244216
Config\ConfigGenerator::class,
245217
],
218+
219+
Command\InstallCommand::class => [Service\InstallationRunner::class],
220+
Command\UpdateCommand::class => [Service\InstallationRunner::class],
246221
Command\SetOptionCommand::class => [
247222
ConfigWriter::class,
248223
Service\ShlinkAssetsHandler::class,

phpunit.xml.dist

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
bootstrap="./vendor/autoload.php"
66
colors="true"
77
cacheDirectory="build/.phpunit.cache"
8-
displayDetailsOnTestsThatTriggerWarnings="true"
8+
displayDetailsOnPhpunitDeprecations="true"
9+
displayDetailsOnTestsThatTriggerDeprecations="true"
10+
displayDetailsOnPhpunitNotices="true"
11+
displayDetailsOnTestsThatTriggerNotices="true"
912
>
1013
<testsuites>
1114
<testsuite name="Installer">

src/Command/AbstractInstallCommand.php

Lines changed: 0 additions & 92 deletions
This file was deleted.

src/Command/InitCommand.php

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,37 @@
44

55
namespace Shlinkio\Shlink\Installer\Command;
66

7-
use Shlinkio\Shlink\Installer\Command\Model\InitOption;
8-
use Shlinkio\Shlink\Installer\Model\CLIOption;
9-
use Shlinkio\Shlink\Installer\Model\ShlinkInitConfig;
7+
use Shlinkio\Shlink\Installer\Command\Model\InitCommandInput;
108
use Shlinkio\Shlink\Installer\Service\InstallationCommandsRunnerInterface;
119
use Shlinkio\Shlink\Installer\Util\InstallationCommand;
10+
use Symfony\Component\Console\Attribute\AsCommand;
11+
use Symfony\Component\Console\Attribute\MapInput;
1212
use Symfony\Component\Console\Command\Command;
1313
use Symfony\Component\Console\Input\InputInterface;
14-
use Symfony\Component\Console\Output\OutputInterface;
1514
use Symfony\Component\Console\Style\SymfonyStyle;
1615

1716
use function array_reduce;
1817

18+
#[AsCommand(
19+
name: InitCommand::NAME,
20+
description: 'Initializes external dependencies required for Shlink to properly work, like DB, cache warmup, '
21+
. 'initial GeoLite DB download, etc',
22+
)]
1923
class InitCommand extends Command
2024
{
2125
public const string NAME = 'init';
2226

23-
private readonly CLIOption $skipInitDb;
24-
private readonly CLIOption $clearDbCache;
25-
private readonly CLIOption $initialApiKey;
26-
private readonly CLIOption $downloadRoadRunnerBin;
27-
private readonly CLIOption $skipDownloadGeoLiteDb;
28-
2927
public function __construct(private readonly InstallationCommandsRunnerInterface $commandsRunner)
3028
{
3129
parent::__construct();
32-
33-
$this->initialApiKey = InitOption::INITIAL_API_KEY->toCLIOption($this);
34-
$this->skipInitDb = InitOption::SKIP_INITIALIZE_DB->toCLIOption($this);
35-
$this->clearDbCache = InitOption::CLEAR_DB_CACHE->toCLIOption($this);
36-
$this->downloadRoadRunnerBin = InitOption::DOWNLOAD_RR_BINARY->toCLIOption($this);
37-
$this->skipDownloadGeoLiteDb = InitOption::SKIP_DOWNLOAD_GEOLITE->toCLIOption($this);
38-
}
39-
40-
protected function configure(): void
41-
{
42-
$this
43-
->setName(self::NAME)
44-
->setDescription(
45-
'Initializes external dependencies required for Shlink to properly work, like DB, cache warmup, '
46-
. 'initial GeoLite DB download, etc',
47-
);
4830
}
4931

50-
protected function execute(InputInterface $input, OutputInterface $output): int
32+
public function __invoke(SymfonyStyle $io, InputInterface $input, #[MapInput] InitCommandInput $inputData): int
5133
{
52-
$config = new ShlinkInitConfig(
53-
initializeDb: ! $this->skipInitDb->get($input),
54-
clearDbCache: $this->clearDbCache->get($input),
55-
downloadRoadrunnerBinary: $this->downloadRoadRunnerBin->get($input),
56-
generateApiKey: $this->initialApiKey->get($input),
57-
downloadGeoLiteDb: ! $this->skipDownloadGeoLiteDb->get($input),
58-
);
59-
$commands = [...InstallationCommand::resolveCommandsForConfig($config)];
60-
$io = new SymfonyStyle($input, $output);
34+
$commands = [...$inputData->resolveCommands()];
6135

6236
return array_reduce($commands, function (bool $carry, array $commandInfo) use ($input, $io): bool {
63-
/** @var array{InstallationCommand, string | null} $commandInfo */
37+
/** @var array{InstallationCommand, string|null} $commandInfo */
6438
[$command, $arg] = $commandInfo;
6539

6640
return $this->commandsRunner->execPhpCommand(
@@ -69,6 +43,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
6943
interactive: $input->isInteractive(),
7044
args: $arg !== null ? [$arg] : [],
7145
) && $carry;
72-
}, initial: true) ? 0 : -1;
46+
}, initial: true) ? self::SUCCESS : self::FAILURE;
7347
}
7448
}

src/Command/InstallCommand.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,24 @@
44

55
namespace Shlinkio\Shlink\Installer\Command;
66

7-
class InstallCommand extends AbstractInstallCommand
7+
use Shlinkio\Shlink\Installer\Service\InstallationRunnerInterface;
8+
use Symfony\Component\Console\Attribute\AsCommand;
9+
use Symfony\Component\Console\Command\Command;
10+
use Symfony\Component\Console\Style\SymfonyStyle;
11+
12+
#[AsCommand(InstallCommand::NAME, 'Guides you through the installation process, to get Shlink up and running')]
13+
class InstallCommand extends Command
814
{
915
public const string NAME = 'install';
1016

11-
protected function configure(): void
17+
public function __construct(private readonly InstallationRunnerInterface $installationRunner)
1218
{
13-
$this
14-
->setName(self::NAME)
15-
->setDescription('Guides you through the installation process, to get Shlink up and running.');
19+
parent::__construct();
1620
}
1721

18-
protected function isUpdate(): bool
22+
public function __invoke(SymfonyStyle $io): int
1923
{
20-
return false;
24+
$initCommand = $this->getApplication()?->find(InitCommand::NAME);
25+
return $this->installationRunner->runInstallation($io, $initCommand);
2126
}
2227
}

0 commit comments

Comments
 (0)