diff --git a/CHANGELOG.md b/CHANGELOG.md index 0402f290..bf87c663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this * [#2472](https://github.com/shlinkio/shlink/issues/2472) Add support for PHP 8.5 ### Changed -* *Nothing* +* [#2424](https://github.com/shlinkio/shlink/issues/2424) Make simple console commands invokable. ### Deprecated * *Nothing* diff --git a/module/CLI/src/Command/Api/InitialApiKeyCommand.php b/module/CLI/src/Command/Api/InitialApiKeyCommand.php index 66968eb3..680135d8 100644 --- a/module/CLI/src/Command/Api/InitialApiKeyCommand.php +++ b/module/CLI/src/Command/Api/InitialApiKeyCommand.php @@ -5,11 +5,15 @@ declare(strict_types=1); namespace Shlinkio\Shlink\CLI\Command\Api; use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface; +use Symfony\Component\Console\Attribute\Argument; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +#[AsCommand( + name: InitialApiKeyCommand::NAME, + description: 'Tries to create initial API key', +)] class InitialApiKeyCommand extends Command { public const string NAME = 'api-key:initial'; @@ -19,22 +23,14 @@ class InitialApiKeyCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setHidden() - ->setName(self::NAME) - ->setDescription('Tries to create initial API key') - ->addArgument('apiKey', InputArgument::REQUIRED, 'The initial API to create'); - } + public function __invoke( + SymfonyStyle $io, + #[Argument('The initial API to create')] string $apiKey, + ): int { + $result = $this->apiKeyService->createInitial($apiKey); - protected function execute(InputInterface $input, OutputInterface $output): int - { - $key = $input->getArgument('apiKey'); - $result = $this->apiKeyService->createInitial($key); - - if ($result === null && $output->isVerbose()) { - $output->writeln('Other API keys already exist. Initial API key creation skipped.'); + if ($result === null && $io->isVerbose()) { + $io->writeln('Other API keys already exist. Initial API key creation skipped.'); } return Command::SUCCESS; diff --git a/module/CLI/src/Command/Config/ReadEnvVarCommand.php b/module/CLI/src/Command/Config/ReadEnvVarCommand.php index e1cef3fd..e3a38be6 100644 --- a/module/CLI/src/Command/Config/ReadEnvVarCommand.php +++ b/module/CLI/src/Command/Config/ReadEnvVarCommand.php @@ -6,9 +6,10 @@ namespace Shlinkio\Shlink\CLI\Command\Config; use Closure; use Shlinkio\Shlink\Core\Config\EnvVars; +use Symfony\Component\Console\Attribute\Argument; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; @@ -18,6 +19,11 @@ use function Shlinkio\Shlink\Core\ArrayUtils\contains; use function Shlinkio\Shlink\Core\enumValues; use function sprintf; +#[AsCommand( + name: ReadEnvVarCommand::NAME, + description: 'Display current value for an env var', + hidden: true, +)] class ReadEnvVarCommand extends Command { public const string NAME = 'env-var:read'; @@ -31,19 +37,10 @@ class ReadEnvVarCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setName(self::NAME) - ->setHidden() - ->setDescription('Display current value for an env var') - ->addArgument('envVar', InputArgument::REQUIRED, 'The env var to read'); - } - protected function interact(InputInterface $input, OutputInterface $output): void { $io = new SymfonyStyle($input, $output); - $envVar = $input->getArgument('envVar'); + $envVar = $input->getArgument('env-var'); $validEnvVars = enumValues(EnvVars::class); if ($envVar === null) { @@ -54,14 +51,14 @@ class ReadEnvVarCommand extends Command throw new InvalidArgumentException(sprintf('%s is not a valid Shlink environment variable', $envVar)); } - $input->setArgument('envVar', $envVar); + $input->setArgument('env-var', $envVar); } - protected function execute(InputInterface $input, OutputInterface $output): int - { - $envVar = $input->getArgument('envVar'); - $output->writeln(formatEnvVarValue(($this->loadEnvVar)($envVar))); - + public function __invoke( + SymfonyStyle $io, + #[Argument(description: 'The env var to read')] string $envVar, + ): int { + $io->writeln(formatEnvVarValue(($this->loadEnvVar)($envVar))); return Command::SUCCESS; } } diff --git a/module/CLI/src/Command/Domain/DomainRedirectsCommand.php b/module/CLI/src/Command/Domain/DomainRedirectsCommand.php index 4c2e4350..1e272c12 100644 --- a/module/CLI/src/Command/Domain/DomainRedirectsCommand.php +++ b/module/CLI/src/Command/Domain/DomainRedirectsCommand.php @@ -7,8 +7,9 @@ namespace Shlinkio\Shlink\CLI\Command\Domain; use Shlinkio\Shlink\Core\Config\NotFoundRedirects; use Shlinkio\Shlink\Core\Domain\DomainServiceInterface; use Shlinkio\Shlink\Core\Domain\Model\DomainItem; +use Symfony\Component\Console\Attribute\Argument; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; @@ -18,6 +19,10 @@ use function array_map; use function sprintf; use function str_contains; +#[AsCommand( + name: DomainRedirectsCommand::NAME, + description: 'Set specific "not found" redirects for individual domains.', +)] class DomainRedirectsCommand extends Command { public const string NAME = 'domain:redirects'; @@ -27,18 +32,6 @@ class DomainRedirectsCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setName(self::NAME) - ->setDescription('Set specific "not found" redirects for individual domains.') - ->addArgument( - 'domain', - InputArgument::REQUIRED, - 'The domain authority to which you want to set the specific redirects', - ); - } - protected function interact(InputInterface $input, OutputInterface $output): void { /** @var string|null $domain */ @@ -67,10 +60,11 @@ class DomainRedirectsCommand extends Command $input->setArgument('domain', str_contains($selectedOption, 'New domain') ? $askNewDomain() : $selectedOption); } - protected function execute(InputInterface $input, OutputInterface $output): int - { - $io = new SymfonyStyle($input, $output); - $domainAuthority = $input->getArgument('domain'); + public function __invoke( + SymfonyStyle $io, + #[Argument('The domain authority to which you want to set the specific redirects', name: 'domain')] + string $domainAuthority, + ): int { $domain = $this->domainService->findByAuthority($domainAuthority); $ask = static function (string $message, string|null $current) use ($io): string|null { diff --git a/module/CLI/src/Command/Domain/ListDomainsCommand.php b/module/CLI/src/Command/Domain/ListDomainsCommand.php index 935d272e..a66d6d7e 100644 --- a/module/CLI/src/Command/Domain/ListDomainsCommand.php +++ b/module/CLI/src/Command/Domain/ListDomainsCommand.php @@ -8,13 +8,17 @@ use Shlinkio\Shlink\CLI\Util\ShlinkTable; use Shlinkio\Shlink\Core\Config\NotFoundRedirectConfigInterface; use Shlinkio\Shlink\Core\Domain\DomainServiceInterface; use Shlinkio\Shlink\Core\Domain\Model\DomainItem; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; use function array_map; +#[AsCommand( + name: ListDomainsCommand::NAME, + description: 'List all domains that have been ever used for some short URL', +)] class ListDomainsCommand extends Command { public const string NAME = 'domain:list'; @@ -24,25 +28,17 @@ class ListDomainsCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setName(self::NAME) - ->setDescription('List all domains that have been ever used for some short URL') - ->addOption( - 'show-redirects', - 'r', - InputOption::VALUE_NONE, - 'Will display an extra column with the information of the "not found" redirects for every domain.', - ); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { + public function __invoke( + SymfonyStyle $io, + #[Option( + 'Will display an extra column with the information of the "not found" redirects for every domain.', + shortcut: 'r', + )] + bool $showRedirects = false, + ): int { $domains = $this->domainService->listDomains(); - $showRedirects = $input->getOption('show-redirects'); $commonFields = ['Domain', 'Is default']; - $table = $showRedirects ? ShlinkTable::withRowSeparators($output) : ShlinkTable::default($output); + $table = $showRedirects ? ShlinkTable::withRowSeparators($io) : ShlinkTable::default($io); $table->render( $showRedirects ? [...$commonFields, '"Not found" redirects'] : $commonFields, @@ -53,7 +49,7 @@ class ListDomainsCommand extends Command ? [ ...$commonValues, $this->notFoundRedirectsToString($domain->notFoundRedirectConfig), - ] + ] : $commonValues; }, $domains), ); diff --git a/module/CLI/src/Command/Integration/MatomoSendVisitsCommand.php b/module/CLI/src/Command/Integration/MatomoSendVisitsCommand.php index c1c22075..f5d8e84c 100644 --- a/module/CLI/src/Command/Integration/MatomoSendVisitsCommand.php +++ b/module/CLI/src/Command/Integration/MatomoSendVisitsCommand.php @@ -8,10 +8,10 @@ use Cake\Chronos\Chronos; use Shlinkio\Shlink\Core\Matomo\MatomoOptions; use Shlinkio\Shlink\Core\Matomo\MatomoVisitSenderInterface; use Shlinkio\Shlink\Core\Matomo\VisitSendingProgressTrackerInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Throwable; @@ -19,22 +19,9 @@ use function Shlinkio\Shlink\Common\buildDateRange; use function Shlinkio\Shlink\Core\dateRangeToHumanFriendly; use function sprintf; -class MatomoSendVisitsCommand extends Command implements VisitSendingProgressTrackerInterface -{ - public const string NAME = 'integration:matomo:send-visits'; - - private readonly bool $matomoEnabled; - private SymfonyStyle $io; - - public function __construct(MatomoOptions $matomoOptions, private readonly MatomoVisitSenderInterface $visitSender) - { - $this->matomoEnabled = $matomoOptions->enabled; - parent::__construct(); - } - - protected function configure(): void - { - $help = <<%command.name% --since 2022-01-01 --until 2022-12-31 - HELP; + HELP, +)] +class MatomoSendVisitsCommand extends Command implements VisitSendingProgressTrackerInterface +{ + public const string NAME = 'integration:matomo:send-visits'; - $this - ->setName(self::NAME) - ->setDescription(sprintf( - '%sSend existing visits to the configured matomo instance', - $this->matomoEnabled ? '' : '[MATOMO INTEGRATION DISABLED] ', - )) - ->setHelp($help) - ->addOption( - 'since', - 's', - InputOption::VALUE_REQUIRED, - 'Only visits created since this date, inclusively, will be sent to Matomo', - ) - ->addOption( - 'until', - 'u', - InputOption::VALUE_REQUIRED, - 'Only visits created until this date, inclusively, will be sent to Matomo', - ); + private readonly bool $matomoEnabled; + private SymfonyStyle $io; + + public function __construct(MatomoOptions $matomoOptions, private readonly MatomoVisitSenderInterface $visitSender) + { + $this->matomoEnabled = $matomoOptions->enabled; + parent::__construct(); } - protected function execute(InputInterface $input, OutputInterface $output): int + protected function configure(): void { - $this->io = new SymfonyStyle($input, $output); + $this->setDescription(sprintf( + '%sSend existing visits to the configured matomo instance', + $this->matomoEnabled ? '' : '[MATOMO INTEGRATION DISABLED] ', + )); + } + + public function __invoke( + SymfonyStyle $io, + InputInterface $input, + #[Option('Only visits created since this date, inclusively, will be sent to Matomo', shortcut: 's')] + string|null $since = null, + #[Option('Only visits created until this date, inclusively, will be sent to Matomo', shortcut: 'u')] + string|null $until = null, + ): int { + $this->io = $io; if (! $this->matomoEnabled) { $this->io->warning('Matomo integration is not enabled in this Shlink instance'); @@ -87,8 +80,6 @@ class MatomoSendVisitsCommand extends Command implements VisitSendingProgressTra } // TODO Validate provided date formats - $since = $input->getOption('since'); - $until = $input->getOption('until'); $dateRange = buildDateRange( startDate: $since !== null ? Chronos::parse($since) : null, endDate: $until !== null ? Chronos::parse($until) : null, diff --git a/module/CLI/src/Command/ShortUrl/DeleteExpiredShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/DeleteExpiredShortUrlsCommand.php index 2b2abd01..626ac136 100644 --- a/module/CLI/src/Command/ShortUrl/DeleteExpiredShortUrlsCommand.php +++ b/module/CLI/src/Command/ShortUrl/DeleteExpiredShortUrlsCommand.php @@ -6,14 +6,18 @@ namespace Shlinkio\Shlink\CLI\Command\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\DeleteShortUrlServiceInterface; use Shlinkio\Shlink\Core\ShortUrl\Model\ExpiredShortUrlsConditions; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use function sprintf; +#[AsCommand( + name: DeleteExpiredShortUrlsCommand::NAME, + description: 'Deletes all short URLs that are considered expired, because they have a validUntil date in the past', +)] class DeleteExpiredShortUrlsCommand extends Command { public const string NAME = 'short-url:delete-expired'; @@ -23,32 +27,17 @@ class DeleteExpiredShortUrlsCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setName(self::NAME) - ->setDescription( - 'Deletes all short URLs that are considered expired, because they have a validUntil date in the past', - ) - ->addOption( - 'evaluate-max-visits', - mode: InputOption::VALUE_NONE, - description: 'Also take into consideration short URLs which have reached their max amount of visits.', - ) - ->addOption('force', 'f', InputOption::VALUE_NONE, 'Delete short URLs with no confirmation') - ->addOption( - 'dry-run', - mode: InputOption::VALUE_NONE, - description: 'Delete short URLs with no confirmation', - ); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $io = new SymfonyStyle($input, $output); - $force = $input->getOption('force') || ! $input->isInteractive(); - $dryRun = $input->getOption('dry-run'); - $conditions = new ExpiredShortUrlsConditions(maxVisitsReached: $input->getOption('evaluate-max-visits')); + public function __invoke( + SymfonyStyle $io, + InputInterface $input, + #[Option('Also take into consideration short URLs which have reached their max amount of visits.')] + bool $evaluateMaxVisits = false, + #[Option('Delete short URLs with no confirmation', shortcut: 'f')] bool $force = false, + #[Option('Only check how many short URLs would be affected, without actually deleting them')] + bool $dryRun = false, + ): int { + $conditions = new ExpiredShortUrlsConditions(maxVisitsReached: $evaluateMaxVisits); + $force = $force || ! $input->isInteractive(); if (! $force && ! $dryRun) { $io->warning([ @@ -69,6 +58,7 @@ class DeleteExpiredShortUrlsCommand extends Command $result = $this->deleteShortUrlService->deleteExpiredShortUrls($conditions); $io->success(sprintf('%s expired short URLs have been deleted', $result)); + return self::SUCCESS; } } diff --git a/module/CLI/src/Command/Tag/DeleteTagsCommand.php b/module/CLI/src/Command/Tag/DeleteTagsCommand.php index 2022a9dc..301cba26 100644 --- a/module/CLI/src/Command/Tag/DeleteTagsCommand.php +++ b/module/CLI/src/Command/Tag/DeleteTagsCommand.php @@ -5,12 +5,12 @@ declare(strict_types=1); namespace Shlinkio\Shlink\CLI\Command\Tag; use Shlinkio\Shlink\Core\Tag\TagServiceInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Attribute\Option; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +#[AsCommand(name: DeleteTagsCommand::NAME, description: 'Deletes one or more tags.')] class DeleteTagsCommand extends Command { public const string NAME = 'tag:delete'; @@ -20,24 +20,13 @@ class DeleteTagsCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setName(self::NAME) - ->setDescription('Deletes one or more tags.') - ->addOption( - 'name', - 't', - InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'The name of the tags to delete', - ); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $io = new SymfonyStyle($input, $output); - $tagNames = $input->getOption('name'); - + /** + * @param string[] $tagNames + */ + public function __invoke( + SymfonyStyle $io, + #[Option('The name of the tags to delete', name: 'name', shortcut: 't')] array $tagNames = [], + ): int { if (empty($tagNames)) { $io->warning('You have to provide at least one tag name'); return self::INVALID; @@ -45,6 +34,7 @@ class DeleteTagsCommand extends Command $this->tagService->deleteTags($tagNames); $io->success('Tags properly deleted'); + return self::SUCCESS; } } diff --git a/module/CLI/src/Command/Tag/ListTagsCommand.php b/module/CLI/src/Command/Tag/ListTagsCommand.php index abd9a0dd..66497737 100644 --- a/module/CLI/src/Command/Tag/ListTagsCommand.php +++ b/module/CLI/src/Command/Tag/ListTagsCommand.php @@ -8,12 +8,13 @@ use Shlinkio\Shlink\CLI\Util\ShlinkTable; use Shlinkio\Shlink\Core\Tag\Model\TagInfo; use Shlinkio\Shlink\Core\Tag\Model\TagsParams; use Shlinkio\Shlink\Core\Tag\TagServiceInterface; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; use function array_map; +#[AsCommand(ListTagsCommand::NAME, 'Lists existing tags.')] class ListTagsCommand extends Command { public const string NAME = 'tag:list'; @@ -23,16 +24,9 @@ class ListTagsCommand extends Command parent::__construct(); } - protected function configure(): void + public function __invoke(SymfonyStyle $io): int { - $this - ->setName(self::NAME) - ->setDescription('Lists existing tags.'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - ShlinkTable::default($output)->render(['Name', 'URLs amount', 'Visits amount'], $this->getTagsRows()); + ShlinkTable::default($io)->render(['Name', 'URLs amount', 'Visits amount'], $this->getTagsRows()); return self::SUCCESS; } diff --git a/module/CLI/src/Command/Tag/RenameTagCommand.php b/module/CLI/src/Command/Tag/RenameTagCommand.php index 2ae0159c..f9e53f28 100644 --- a/module/CLI/src/Command/Tag/RenameTagCommand.php +++ b/module/CLI/src/Command/Tag/RenameTagCommand.php @@ -8,12 +8,12 @@ use Shlinkio\Shlink\Core\Exception\TagConflictException; use Shlinkio\Shlink\Core\Exception\TagNotFoundException; use Shlinkio\Shlink\Core\Model\Renaming; use Shlinkio\Shlink\Core\Tag\TagServiceInterface; +use Symfony\Component\Console\Attribute\Argument; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +#[AsCommand(RenameTagCommand::NAME, 'Renames one existing tag.')] class RenameTagCommand extends Command { public const string NAME = 'tag:rename'; @@ -23,21 +23,11 @@ class RenameTagCommand extends Command parent::__construct(); } - protected function configure(): void - { - $this - ->setName(self::NAME) - ->setDescription('Renames one existing tag.') - ->addArgument('oldName', InputArgument::REQUIRED, 'Current name of the tag.') - ->addArgument('newName', InputArgument::REQUIRED, 'New name of the tag.'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $io = new SymfonyStyle($input, $output); - $oldName = $input->getArgument('oldName'); - $newName = $input->getArgument('newName'); - + public function __invoke( + SymfonyStyle $io, + #[Argument('Current name of the tag.')] string $oldName, + #[Argument('New name of the tag.')] string $newName, + ): int { try { $this->tagService->renameTag(Renaming::fromNames($oldName, $newName)); $io->success('Tag properly renamed.'); diff --git a/module/CLI/src/Command/Visit/DownloadGeoLiteDbCommand.php b/module/CLI/src/Command/Visit/DownloadGeoLiteDbCommand.php index 4d58a7d3..f76a4dbc 100644 --- a/module/CLI/src/Command/Visit/DownloadGeoLiteDbCommand.php +++ b/module/CLI/src/Command/Visit/DownloadGeoLiteDbCommand.php @@ -8,14 +8,17 @@ use Shlinkio\Shlink\Core\Exception\GeolocationDbUpdateFailedException; use Shlinkio\Shlink\Core\Geolocation\GeolocationDbUpdaterInterface; use Shlinkio\Shlink\Core\Geolocation\GeolocationDownloadProgressHandlerInterface; use Shlinkio\Shlink\Core\Geolocation\GeolocationResult; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use function sprintf; +#[AsCommand( + DownloadGeoLiteDbCommand::NAME, + 'Checks if the GeoLite2 db file is too old or it does not exist, and tries to download an up-to-date copy if so.', +)] class DownloadGeoLiteDbCommand extends Command implements GeolocationDownloadProgressHandlerInterface { public const string NAME = 'visit:download-db'; @@ -28,19 +31,9 @@ class DownloadGeoLiteDbCommand extends Command implements GeolocationDownloadPro parent::__construct(); } - protected function configure(): void + public function __invoke(SymfonyStyle $io): int { - $this - ->setName(self::NAME) - ->setDescription( - 'Checks if the GeoLite2 db file is too old or it does not exist, and tries to download an up-to-date ' - . 'copy if so.', - ); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $this->io = new SymfonyStyle($input, $output); + $this->io = $io; try { $result = $this->dbUpdater->checkDbUpdate($this); diff --git a/module/CLI/test/Command/Api/InitialApiKeyCommandTest.php b/module/CLI/test/Command/Api/InitialApiKeyCommandTest.php index e86cf0e5..b2311613 100644 --- a/module/CLI/test/Command/Api/InitialApiKeyCommandTest.php +++ b/module/CLI/test/Command/Api/InitialApiKeyCommandTest.php @@ -35,7 +35,7 @@ class InitialApiKeyCommandTest extends TestCase $this->apiKeyService->expects($this->once())->method('createInitial')->with('the_key')->willReturn($result); $this->commandTester->execute( - ['apiKey' => 'the_key'], + ['api-key' => 'the_key'], ['verbosity' => $verbose ? OutputInterface::VERBOSITY_VERBOSE : OutputInterface::VERBOSITY_NORMAL], ); $output = $this->commandTester->getDisplay(); diff --git a/module/CLI/test/Command/Config/ReadEnvVarCommandTest.php b/module/CLI/test/Command/Config/ReadEnvVarCommandTest.php index c377cf86..e90f94af 100644 --- a/module/CLI/test/Command/Config/ReadEnvVarCommandTest.php +++ b/module/CLI/test/Command/Config/ReadEnvVarCommandTest.php @@ -28,13 +28,13 @@ class ReadEnvVarCommandTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('foo is not a valid Shlink environment variable'); - $this->commandTester->execute(['envVar' => 'foo']); + $this->commandTester->execute(['env-var' => 'foo']); } #[Test] public function valueIsPrintedIfProvidedEnvVarIsValid(): void { - $this->commandTester->execute(['envVar' => EnvVars::BASE_PATH->value]); + $this->commandTester->execute(['env-var' => EnvVars::BASE_PATH->value]); $output = $this->commandTester->getDisplay(); self::assertStringNotContainsString('Select the env var to read', $output); diff --git a/module/CLI/test/Command/Tag/RenameTagCommandTest.php b/module/CLI/test/Command/Tag/RenameTagCommandTest.php index e7fb630d..8681239a 100644 --- a/module/CLI/test/Command/Tag/RenameTagCommandTest.php +++ b/module/CLI/test/Command/Tag/RenameTagCommandTest.php @@ -36,8 +36,8 @@ class RenameTagCommandTest extends TestCase )->willThrowException(TagNotFoundException::fromTag('foo')); $this->commandTester->execute([ - 'oldName' => $oldName, - 'newName' => $newName, + 'old-name' => $oldName, + 'new-name' => $newName, ]); $output = $this->commandTester->getDisplay(); @@ -54,8 +54,8 @@ class RenameTagCommandTest extends TestCase )->willReturn(new Tag($newName)); $this->commandTester->execute([ - 'oldName' => $oldName, - 'newName' => $newName, + 'old-name' => $oldName, + 'new-name' => $newName, ]); $output = $this->commandTester->getDisplay();