From b3c9b7faf71bc13688e52bc8d487134e3004fc9b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 23 May 2023 17:24:39 +0200 Subject: [PATCH 01/59] [7.0] Bump to PHP 8.2 minimum --- composer.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index 618cbcac9..ef0925176 100644 --- a/composer.json +++ b/composer.json @@ -16,30 +16,30 @@ } ], "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" + "symfony/string": "^6.4|^7.0" }, "require-dev": { - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", "psr/log": "^1|^2|^3" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" }, From 28424b5ff904999f66f2067a54bd22a0291ea2f5 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 13 Jun 2023 13:07:33 +0200 Subject: [PATCH 02/59] [Console] Remove deprecations across the component --- Application.php | 14 +----- CHANGELOG.md | 7 +++ Command/Command.php | 59 +++----------------------- Command/CompleteCommand.php | 10 ----- Command/DumpCompletionCommand.php | 10 ----- Command/LazyCommand.php | 11 ++--- Command/SignalableCommandInterface.php | 4 +- Formatter/NullOutputFormatterStyle.php | 10 +---- Formatter/OutputFormatterStyle.php | 10 +---- Helper/Helper.php | 5 +-- Input/InputArgument.php | 5 +-- Input/InputOption.php | 5 +-- Input/StringInput.php | 4 -- Question/Question.php | 10 +---- Tests/Command/CommandTest.php | 50 ---------------------- 15 files changed, 28 insertions(+), 186 deletions(-) diff --git a/Application.php b/Application.php index b7aaa6a29..f8526ae5c 100644 --- a/Application.php +++ b/Application.php @@ -1026,11 +1026,6 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI // If the command is signalable, we call the handleSignal() method if (\in_array($signal, $commandSignals, true)) { $exitCode = $command->handleSignal($signal, $exitCode); - // BC layer for Symfony <= 5 - if (null === $exitCode) { - trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); - $exitCode = 0; - } } if (false !== $exitCode) { @@ -1045,14 +1040,7 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI foreach ($commandSignals as $signal) { $this->signalRegistry->register($signal, function (int $signal) use ($command): void { - $exitCode = $command->handleSignal($signal); - // BC layer for Symfony <= 5 - if (null === $exitCode) { - trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', get_debug_type($command)); - $exitCode = 0; - } - - if (false !== $exitCode) { + if (false !== $exitCode = $command->handleSignal($signal)) { exit($exitCode); } }); diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b8f5a70..1666fa4bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +7.0 +--- + + * Remove `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead + * Passing null to `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()` and `Question::setAutocompleterCallback/setValidator()` must be done explicitly + * Remove `StringInput::REGEX_STRING` + 6.4 --- diff --git a/Command/Command.php b/Command/Command.php index 704b112d1..fae37b686 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -39,20 +39,6 @@ class Command public const FAILURE = 1; public const INVALID = 2; - /** - * @var string|null The default command name - * - * @deprecated since Symfony 6.1, use the AsCommand attribute instead - */ - protected static $defaultName; - - /** - * @var string|null The default command description - * - * @deprecated since Symfony 6.1, use the AsCommand attribute instead - */ - protected static $defaultDescription; - private ?Application $application = null; private ?string $name = null; private ?string $processTitle = null; @@ -70,40 +56,20 @@ class Command public static function getDefaultName(): ?string { - $class = static::class; - - if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) { + if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class)) { return $attribute[0]->newInstance()->name; } - $r = new \ReflectionProperty($class, 'defaultName'); - - if ($class !== $r->class || null === static::$defaultName) { - return null; - } - - trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); - - return static::$defaultName; + return null; } public static function getDefaultDescription(): ?string { - $class = static::class; - - if ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class)) { + if ($attribute = (new \ReflectionClass(static::class))->getAttributes(AsCommand::class)) { return $attribute[0]->newInstance()->description; } - $r = new \ReflectionProperty($class, 'defaultDescription'); - - if ($class !== $r->class || null === static::$defaultDescription) { - return null; - } - - trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); - - return static::$defaultDescription; + return null; } /** @@ -152,11 +118,8 @@ public function ignoreValidationErrors() /** * @return void */ - public function setApplication(Application $application = null) + public function setApplication(?Application $application) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } $this->application = $application; if ($application) { $this->setHelperSet($application->getHelperSet()); @@ -460,12 +423,8 @@ public function getNativeDefinition(): InputDefinition * * @throws InvalidArgumentException When argument mode is not valid */ - public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = null */): static + public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static { - $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; - if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { - throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); - } $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); @@ -484,12 +443,8 @@ public function addArgument(string $name, int $mode = null, string $description * * @throws InvalidArgumentException If option mode is invalid or incompatible */ - public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static { - $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; - if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { - throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); - } $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); diff --git a/Command/CompleteCommand.php b/Command/CompleteCommand.php index 058578d8b..00dd05770 100644 --- a/Command/CompleteCommand.php +++ b/Command/CompleteCommand.php @@ -34,16 +34,6 @@ final class CompleteCommand extends Command { public const COMPLETION_API_VERSION = '1'; - /** - * @deprecated since Symfony 6.1 - */ - protected static $defaultName = '|_complete'; - - /** - * @deprecated since Symfony 6.1 - */ - protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; - private $completionOutputs; private $isDebug = false; diff --git a/Command/DumpCompletionCommand.php b/Command/DumpCompletionCommand.php index 51b613a14..be6f54592 100644 --- a/Command/DumpCompletionCommand.php +++ b/Command/DumpCompletionCommand.php @@ -27,16 +27,6 @@ #[AsCommand(name: 'completion', description: 'Dump the shell completion script')] final class DumpCompletionCommand extends Command { - /** - * @deprecated since Symfony 6.1 - */ - protected static $defaultName = 'completion'; - - /** - * @deprecated since Symfony 6.1 - */ - protected static $defaultDescription = 'Dump the shell completion script'; - private array $supportedShells; protected function configure(): void diff --git a/Command/LazyCommand.php b/Command/LazyCommand.php index d56058221..7279724a6 100644 --- a/Command/LazyCommand.php +++ b/Command/LazyCommand.php @@ -45,11 +45,8 @@ public function ignoreValidationErrors(): void $this->getCommand()->ignoreValidationErrors(); } - public function setApplication(Application $application = null): void + public function setApplication(?Application $application): void { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } if ($this->command instanceof parent) { $this->command->setApplication($application); } @@ -116,9 +113,8 @@ public function getNativeDefinition(): InputDefinition /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ - public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addArgument(string $name, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static { - $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues); return $this; @@ -127,9 +123,8 @@ public function addArgument(string $name, int $mode = null, string $description /** * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion */ - public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null /* array|\Closure $suggestedValues = [] */): static + public function addOption(string $name, string|array $shortcut = null, int $mode = null, string $description = '', mixed $default = null, array|\Closure $suggestedValues = []): static { - $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); return $this; diff --git a/Command/SignalableCommandInterface.php b/Command/SignalableCommandInterface.php index 4d0876003..7ebffede1 100644 --- a/Command/SignalableCommandInterface.php +++ b/Command/SignalableCommandInterface.php @@ -26,9 +26,7 @@ public function getSubscribedSignals(): array; /** * The method will be called when the application is signaled. * - * @param int|false $previousExitCode - * @return int|false The exit code to return or false to continue the normal execution */ - public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); + public function handleSignal(int $signal, int|false $previousExitCode = 0); } diff --git a/Formatter/NullOutputFormatterStyle.php b/Formatter/NullOutputFormatterStyle.php index c2ce7d14c..06fa6e40b 100644 --- a/Formatter/NullOutputFormatterStyle.php +++ b/Formatter/NullOutputFormatterStyle.php @@ -21,19 +21,13 @@ public function apply(string $text): string return $text; } - public function setBackground(string $color = null): void + public function setBackground(?string $color): void { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } // do nothing } - public function setForeground(string $color = null): void + public function setForeground(?string $color): void { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } // do nothing } diff --git a/Formatter/OutputFormatterStyle.php b/Formatter/OutputFormatterStyle.php index 346a474c6..f075e881d 100644 --- a/Formatter/OutputFormatterStyle.php +++ b/Formatter/OutputFormatterStyle.php @@ -41,22 +41,16 @@ public function __construct(string $foreground = null, string $background = null /** * @return void */ - public function setForeground(string $color = null) + public function setForeground(?string $color) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); } /** * @return void */ - public function setBackground(string $color = null) + public function setBackground(?string $color) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); } diff --git a/Helper/Helper.php b/Helper/Helper.php index 3631b30f6..c80c1f468 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -26,11 +26,8 @@ abstract class Helper implements HelperInterface /** * @return void */ - public function setHelperSet(HelperSet $helperSet = null) + public function setHelperSet(?HelperSet $helperSet) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } $this->helperSet = $helperSet; } diff --git a/Input/InputArgument.php b/Input/InputArgument.php index 5cb151488..fa57f5d0d 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -95,11 +95,8 @@ public function isArray(): bool * * @throws LogicException When incorrect default value is given */ - public function setDefault(string|bool|int|float|array $default = null) + public function setDefault(string|bool|int|float|array|null $default) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } if ($this->isRequired() && null !== $default) { throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); } diff --git a/Input/InputOption.php b/Input/InputOption.php index fdf88dcc2..c9e8aa82b 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -181,11 +181,8 @@ public function isNegatable(): bool /** * @return void */ - public function setDefault(string|bool|int|float|array $default = null) + public function setDefault(string|bool|int|float|array|null $default) { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); } diff --git a/Input/StringInput.php b/Input/StringInput.php index 82bd21440..33f0f4b39 100644 --- a/Input/StringInput.php +++ b/Input/StringInput.php @@ -24,10 +24,6 @@ */ class StringInput extends ArgvInput { - /** - * @deprecated since Symfony 6.1 - */ - public const REGEX_STRING = '([^\s]+?)(?:\s|(? \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } if ($this->hidden && null !== $callback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } @@ -194,11 +191,8 @@ public function setAutocompleterCallback(callable $callback = null): static * * @return $this */ - public function setValidator(callable $validator = null): static + public function setValidator(?callable $validator): static { - if (1 > \func_num_args()) { - trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); - } $this->validator = null === $validator ? null : $validator(...); return $this; diff --git a/Tests/Command/CommandTest.php b/Tests/Command/CommandTest.php index f85280fed..48ba92706 100644 --- a/Tests/Command/CommandTest.php +++ b/Tests/Command/CommandTest.php @@ -442,37 +442,6 @@ public function testCommandAttribute() $this->assertSame(['f'], $command->getAliases()); } - /** - * @group legacy - */ - public function testDefaultNameProperty() - { - $this->expectDeprecation('Since symfony/console 6.1: Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "Symfony\Component\Console\Attribute\AsCommand" attribute to the "Symfony\Component\Console\Tests\Command\MyCommand" class instead.'); - - $this->assertSame('my:command', MyCommand::getDefaultName()); - } - - /** - * @group legacy - */ - public function testDefaultDescriptionProperty() - { - $this->expectDeprecation('Since symfony/console 6.1: Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "Symfony\Component\Console\Attribute\AsCommand" attribute to the "Symfony\Component\Console\Tests\Command\MyCommand" class instead.'); - - $this->assertSame('This is a command I wrote all by myself', MyCommand::getDefaultDescription()); - } - - /** - * @group legacy - */ - public function testStaticDefaultProperties() - { - $command = new MyCommand(); - - $this->assertSame('my:command', $command->getName()); - $this->assertSame('This is a command I wrote all by myself', $command->getDescription()); - } - public function testAttributeOverridesProperty() { $this->assertSame('my:command', MyAnnotatedCommand::getDefaultName()); @@ -518,29 +487,10 @@ class Php8Command2 extends Command { } -class MyCommand extends Command -{ - /** - * @deprecated since Symfony 6.1 - */ - protected static $defaultName = 'my:command'; - - /** - * @deprecated since Symfony 6.1 - */ - protected static $defaultDescription = 'This is a command I wrote all by myself'; -} - #[AsCommand(name: 'my:command', description: 'This is a command I wrote all by myself')] class MyAnnotatedCommand extends Command { - /** - * @deprecated since Symfony 6.1 - */ protected static $defaultName = 'i-shall-be-ignored'; - /** - * @deprecated since Symfony 6.1 - */ protected static $defaultDescription = 'This description should be ignored.'; } From f351fd9427ffe861090c76a65901bb746e847055 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 30 Jun 2023 18:53:02 +0200 Subject: [PATCH 03/59] Remove BC layers related to new methods and new parameters --- CHANGELOG.md | 1 + Input/InputInterface.php | 10 +++++++--- Tests/EventListener/ErrorListenerTest.php | 13 ------------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1666fa4bb..1406d75f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.0 --- + * Add method `__toString()` to `InputInterface` * Remove `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead * Passing null to `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()` and `Question::setAutocompleterCallback/setValidator()` must be done explicitly * Remove `StringInput::REGEX_STRING` diff --git a/Input/InputInterface.php b/Input/InputInterface.php index aaed5fd01..ca22bdbba 100644 --- a/Input/InputInterface.php +++ b/Input/InputInterface.php @@ -18,9 +18,6 @@ * InputInterface is the interface implemented by all input classes. * * @author Fabien Potencier - * - * @method string __toString() Returns a stringified representation of the args passed to the command. - * InputArguments MUST be escaped as well as the InputOption values passed to the command. */ interface InputInterface { @@ -147,4 +144,11 @@ public function isInteractive(): bool; * @return void */ public function setInteractive(bool $interactive); + + /** + * Returns a stringified representation of the args passed to the command. + * + * InputArguments MUST be escaped as well as the InputOption values passed to the command. + */ + public function __toString(): string; } diff --git a/Tests/EventListener/ErrorListenerTest.php b/Tests/EventListener/ErrorListenerTest.php index 6ad89dc52..10bed7d03 100644 --- a/Tests/EventListener/ErrorListenerTest.php +++ b/Tests/EventListener/ErrorListenerTest.php @@ -107,19 +107,6 @@ public function testAllKindsOfInputCanBeLogged() $listener->onConsoleTerminate($this->getConsoleTerminateEvent(new StringInput('test:run --foo=bar'), 255)); } - public function testCommandNameIsDisplayedForNonStringableInput() - { - $logger = $this->createMock(LoggerInterface::class); - $logger - ->expects($this->once()) - ->method('debug') - ->with('Command "{command}" exited with code "{code}"', ['command' => 'test:run', 'code' => 255]) - ; - - $listener = new ErrorListener($logger); - $listener->onConsoleTerminate($this->getConsoleTerminateEvent($this->createMock(InputInterface::class), 255)); - } - private function getConsoleTerminateEvent(InputInterface $input, $exitCode) { return new ConsoleTerminateEvent(new Command('test:run'), $input, $this->createMock(OutputInterface::class), $exitCode); From 14816cde7c93be7037a191775637fc75e93cb81b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 4 Jul 2023 14:50:59 +0200 Subject: [PATCH 04/59] [7.0] Remove remaining deprecated code paths --- CHANGELOG.md | 2 +- Tests/Command/CommandTest.php | 3 --- composer.json | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1406d75f6..fe4425a9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ CHANGELOG * Add method `__toString()` to `InputInterface` * Remove `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead - * Passing null to `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()` and `Question::setAutocompleterCallback/setValidator()` must be done explicitly + * Require explicit argument when calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()` and `Question::setAutocompleterCallback/setValidator()` * Remove `StringInput::REGEX_STRING` 6.4 diff --git a/Tests/Command/CommandTest.php b/Tests/Command/CommandTest.php index 48ba92706..6c1c60d77 100644 --- a/Tests/Command/CommandTest.php +++ b/Tests/Command/CommandTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Console\Tests\Command; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\Console\Application; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -29,8 +28,6 @@ class CommandTest extends TestCase { - use ExpectDeprecationTrait; - protected static $fixturesPath; public static function setUpBeforeClass(): void diff --git a/composer.json b/composer.json index ef0925176..5ca14fd4c 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ ], "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", "symfony/string": "^6.4|^7.0" From 8b83b2fc425bd48e3e4e863da3a1c8f74d9dac91 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 2 Jul 2023 23:52:21 +0200 Subject: [PATCH 05/59] [Components] Convert to native return types --- Application.php | 71 ++++--------- Command/Command.php | 36 ++----- Command/HelpCommand.php | 10 +- Command/ListCommand.php | 5 +- Command/SignalableCommandInterface.php | 2 +- DependencyInjection/AddConsoleCommandPass.php | 5 +- Descriptor/DescriptorInterface.php | 5 +- EventListener/ErrorListener.php | 10 +- Formatter/OutputFormatter.php | 15 +-- Formatter/OutputFormatterInterface.php | 8 +- Formatter/OutputFormatterStyle.php | 25 +---- Formatter/OutputFormatterStyleInterface.php | 20 +--- Formatter/OutputFormatterStyleStack.php | 8 +- .../WrappableOutputFormatterInterface.php | 4 +- Helper/DescriptorHelper.php | 4 +- Helper/Helper.php | 20 +--- Helper/HelperInterface.php | 8 +- Helper/HelperSet.php | 5 +- Helper/InputAwareHelper.php | 5 +- Helper/ProgressIndicator.php | 20 +--- Helper/QuestionHelper.php | 12 +-- Helper/SymfonyQuestionHelper.php | 10 +- Helper/Table.php | 10 +- Input/ArgvInput.php | 10 +- Input/ArrayInput.php | 5 +- Input/Input.php | 33 ++---- Input/InputArgument.php | 4 +- Input/InputAwareInterface.php | 4 +- Input/InputDefinition.php | 28 ++--- Input/InputInterface.php | 32 ++---- Input/InputOption.php | 5 +- Input/StreamableInputInterface.php | 4 +- Output/BufferedOutput.php | 5 +- Output/ConsoleOutput.php | 20 +--- Output/ConsoleOutputInterface.php | 5 +- Output/ConsoleSectionOutput.php | 13 +-- Output/NullOutput.php | 25 +---- Output/Output.php | 29 ++--- Output/OutputInterface.php | 21 +--- Output/StreamOutput.php | 5 +- Output/TrimmedBufferOutput.php | 5 +- Question/Question.php | 5 +- Style/OutputStyle.php | 35 ++---- Style/StyleInterface.php | 56 +++------- Style/SymfonyStyle.php | 100 ++++-------------- Tests/ApplicationTest.php | 6 +- Tests/ConsoleEventsTest.php | 2 +- Tests/EventListener/ErrorListenerTest.php | 2 +- Tests/Output/OutputTest.php | 2 +- Tests/SignalRegistry/SignalRegistryTest.php | 2 +- 50 files changed, 181 insertions(+), 600 deletions(-) diff --git a/Application.php b/Application.php index f8526ae5c..9908bfcce 100644 --- a/Application.php +++ b/Application.php @@ -110,10 +110,7 @@ public function setDispatcher(EventDispatcherInterface $dispatcher): void $this->dispatcher = $dispatcher; } - /** - * @return void - */ - public function setCommandLoader(CommandLoaderInterface $commandLoader) + public function setCommandLoader(CommandLoaderInterface $commandLoader): void { $this->commandLoader = $commandLoader; } @@ -127,10 +124,7 @@ public function getSignalRegistry(): SignalRegistry return $this->signalRegistry; } - /** - * @return void - */ - public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) + public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent): void { $this->signalsToDispatchEvent = $signalsToDispatchEvent; } @@ -220,7 +214,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null * * @return int 0 if everything went fine, or an error code */ - public function doRun(InputInterface $input, OutputInterface $output) + public function doRun(InputInterface $input, OutputInterface $output): int { if (true === $input->hasParameterOption(['--version', '-V'], true)) { $output->writeln($this->getLongVersion()); @@ -323,17 +317,11 @@ public function doRun(InputInterface $input, OutputInterface $output) return $exitCode; } - /** - * @return void - */ - public function reset() + public function reset(): void { } - /** - * @return void - */ - public function setHelperSet(HelperSet $helperSet) + public function setHelperSet(HelperSet $helperSet): void { $this->helperSet = $helperSet; } @@ -346,10 +334,7 @@ public function getHelperSet(): HelperSet return $this->helperSet ??= $this->getDefaultHelperSet(); } - /** - * @return void - */ - public function setDefinition(InputDefinition $definition) + public function setDefinition(InputDefinition $definition): void { $this->definition = $definition; } @@ -419,10 +404,8 @@ public function areExceptionsCaught(): bool /** * Sets whether to catch exceptions or not during commands execution. - * - * @return void */ - public function setCatchExceptions(bool $boolean) + public function setCatchExceptions(bool $boolean): void { $this->catchExceptions = $boolean; } @@ -437,10 +420,8 @@ public function isAutoExitEnabled(): bool /** * Sets whether to automatically exit after a command execution or not. - * - * @return void */ - public function setAutoExit(bool $boolean) + public function setAutoExit(bool $boolean): void { $this->autoExit = $boolean; } @@ -455,10 +436,8 @@ public function getName(): string /** * Sets the application name. - * - * @return void */ - public function setName(string $name) + public function setName(string $name): void { $this->name = $name; } @@ -473,20 +452,16 @@ public function getVersion(): string /** * Sets the application version. - * - * @return void */ - public function setVersion(string $version) + public function setVersion(string $version): void { $this->version = $version; } /** * Returns the long version of the application. - * - * @return string */ - public function getLongVersion() + public function getLongVersion(): string { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { @@ -513,10 +488,8 @@ public function register(string $name): Command * If a Command is not enabled it will not be added. * * @param Command[] $commands An array of commands - * - * @return void */ - public function addCommands(array $commands) + public function addCommands(array $commands): void { foreach ($commands as $command) { $this->add($command); @@ -528,10 +501,8 @@ public function addCommands(array $commands) * * If a command with the same name already exists, it will be overridden. * If the command is not enabled it will not be added. - * - * @return Command|null */ - public function add(Command $command) + public function add(Command $command): ?Command { $this->init(); @@ -564,11 +535,9 @@ public function add(Command $command) /** * Returns a registered command by name or alias. * - * @return Command - * * @throws CommandNotFoundException When given command name does not exist */ - public function get(string $name) + public function get(string $name): Command { $this->init(); @@ -671,11 +640,9 @@ public function findNamespace(string $namespace): string * Contrary to get, this command tries to find the best * match if you give it an abbreviation of a name or alias. * - * @return Command - * * @throws CommandNotFoundException When command name is incorrect or ambiguous */ - public function find(string $name) + public function find(string $name): Command { $this->init(); @@ -783,7 +750,7 @@ public function find(string $name) * * @return Command[] */ - public function all(string $namespace = null) + public function all(string $namespace = null): array { $this->init(); @@ -924,10 +891,8 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo /** * Configures the input and output instances based on the user arguments and options. - * - * @return void */ - protected function configureIO(InputInterface $input, OutputInterface $output) + protected function configureIO(InputInterface $input, OutputInterface $output): void { if (true === $input->hasParameterOption(['--ansi'], true)) { $output->setDecorated(true); @@ -992,7 +957,7 @@ protected function configureIO(InputInterface $input, OutputInterface $output) * * @return int 0 if everything went fine, or an error code */ - protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) + protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int { foreach ($command->getHelperSet() as $helper) { if ($helper instanceof InputAwareInterface) { diff --git a/Command/Command.php b/Command/Command.php index fae37b686..017026e1e 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -107,18 +107,13 @@ public function __construct(string $name = null) * Ignores validation errors. * * This is mainly useful for the help command. - * - * @return void */ - public function ignoreValidationErrors() + public function ignoreValidationErrors(): void { $this->ignoreValidationErrors = true; } - /** - * @return void - */ - public function setApplication(?Application $application) + public function setApplication(?Application $application): void { $this->application = $application; if ($application) { @@ -130,10 +125,7 @@ public function setApplication(?Application $application) $this->fullDefinition = null; } - /** - * @return void - */ - public function setHelperSet(HelperSet $helperSet) + public function setHelperSet(HelperSet $helperSet): void { $this->helperSet = $helperSet; } @@ -159,20 +151,16 @@ public function getApplication(): ?Application * * Override this to check for x or y and return false if the command cannot * run properly under the current conditions. - * - * @return bool */ - public function isEnabled() + public function isEnabled(): bool { return true; } /** * Configures the current command. - * - * @return void */ - protected function configure() + protected function configure(): void { } @@ -190,7 +178,7 @@ protected function configure() * * @see setCode() */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { throw new LogicException('You must override the execute() method in the concrete command class.'); } @@ -201,10 +189,8 @@ protected function execute(InputInterface $input, OutputInterface $output) * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. - * - * @return void */ - protected function interact(InputInterface $input, OutputInterface $output) + protected function interact(InputInterface $input, OutputInterface $output): void { } @@ -217,10 +203,8 @@ protected function interact(InputInterface $input, OutputInterface $output) * * @see InputInterface::bind() * @see InputInterface::validate() - * - * @return void */ - protected function initialize(InputInterface $input, OutputInterface $output) + protected function initialize(InputInterface $input, OutputInterface $output): void { } @@ -650,12 +634,10 @@ public function getUsages(): array /** * Gets a helper instance by name. * - * @return HelperInterface - * * @throws LogicException if no HelperSet is defined * @throws InvalidArgumentException if the helper is not defined */ - public function getHelper(string $name): mixed + public function getHelper(string $name): HelperInterface { if (null === $this->helperSet) { throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); diff --git a/Command/HelpCommand.php b/Command/HelpCommand.php index e6447b050..a2a72dab4 100644 --- a/Command/HelpCommand.php +++ b/Command/HelpCommand.php @@ -27,10 +27,7 @@ class HelpCommand extends Command { private Command $command; - /** - * @return void - */ - protected function configure() + protected function configure(): void { $this->ignoreValidationErrors(); @@ -57,10 +54,7 @@ protected function configure() ; } - /** - * @return void - */ - public function setCommand(Command $command) + public function setCommand(Command $command): void { $this->command = $command; } diff --git a/Command/ListCommand.php b/Command/ListCommand.php index 5850c3d7b..61b4b1b3e 100644 --- a/Command/ListCommand.php +++ b/Command/ListCommand.php @@ -25,10 +25,7 @@ */ class ListCommand extends Command { - /** - * @return void - */ - protected function configure() + protected function configure(): void { $this ->setName('list') diff --git a/Command/SignalableCommandInterface.php b/Command/SignalableCommandInterface.php index 7ebffede1..40b301d18 100644 --- a/Command/SignalableCommandInterface.php +++ b/Command/SignalableCommandInterface.php @@ -28,5 +28,5 @@ public function getSubscribedSignals(): array; * * @return int|false The exit code to return or false to continue the normal execution */ - public function handleSignal(int $signal, int|false $previousExitCode = 0); + public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false; } diff --git a/DependencyInjection/AddConsoleCommandPass.php b/DependencyInjection/AddConsoleCommandPass.php index 27705ddb6..f712c614a 100644 --- a/DependencyInjection/AddConsoleCommandPass.php +++ b/DependencyInjection/AddConsoleCommandPass.php @@ -29,10 +29,7 @@ */ class AddConsoleCommandPass implements CompilerPassInterface { - /** - * @return void - */ - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { $commandServices = $container->findTaggedServiceIds('console.command', true); $lazyCommandMap = []; diff --git a/Descriptor/DescriptorInterface.php b/Descriptor/DescriptorInterface.php index ab468a256..04e5a7c86 100644 --- a/Descriptor/DescriptorInterface.php +++ b/Descriptor/DescriptorInterface.php @@ -20,8 +20,5 @@ */ interface DescriptorInterface { - /** - * @return void - */ - public function describe(OutputInterface $output, object $object, array $options = []); + public function describe(OutputInterface $output, object $object, array $options = []): void; } diff --git a/EventListener/ErrorListener.php b/EventListener/ErrorListener.php index 9925a5f74..5c38e8ef8 100644 --- a/EventListener/ErrorListener.php +++ b/EventListener/ErrorListener.php @@ -31,10 +31,7 @@ public function __construct(LoggerInterface $logger = null) $this->logger = $logger; } - /** - * @return void - */ - public function onConsoleError(ConsoleErrorEvent $event) + public function onConsoleError(ConsoleErrorEvent $event): void { if (null === $this->logger) { return; @@ -51,10 +48,7 @@ public function onConsoleError(ConsoleErrorEvent $event) $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); } - /** - * @return void - */ - public function onConsoleTerminate(ConsoleTerminateEvent $event) + public function onConsoleTerminate(ConsoleTerminateEvent $event): void { if (null === $this->logger) { return; diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php index 9cb631048..4360d3cf9 100644 --- a/Formatter/OutputFormatter.php +++ b/Formatter/OutputFormatter.php @@ -81,10 +81,7 @@ public function __construct(bool $decorated = false, array $styles = []) $this->styleStack = new OutputFormatterStyleStack(); } - /** - * @return void - */ - public function setDecorated(bool $decorated) + public function setDecorated(bool $decorated): void { $this->decorated = $decorated; } @@ -94,10 +91,7 @@ public function isDecorated(): bool return $this->decorated; } - /** - * @return void - */ - public function setStyle(string $name, OutputFormatterStyleInterface $style) + public function setStyle(string $name, OutputFormatterStyleInterface $style): void { $this->styles[strtolower($name)] = $style; } @@ -121,10 +115,7 @@ public function format(?string $message): ?string return $this->formatAndWrap($message, 0); } - /** - * @return string - */ - public function formatAndWrap(?string $message, int $width) + public function formatAndWrap(?string $message, int $width): string { if (null === $message) { return ''; diff --git a/Formatter/OutputFormatterInterface.php b/Formatter/OutputFormatterInterface.php index 433cd4197..947347fa7 100644 --- a/Formatter/OutputFormatterInterface.php +++ b/Formatter/OutputFormatterInterface.php @@ -20,10 +20,8 @@ interface OutputFormatterInterface { /** * Sets the decorated flag. - * - * @return void */ - public function setDecorated(bool $decorated); + public function setDecorated(bool $decorated): void; /** * Whether the output will decorate messages. @@ -32,10 +30,8 @@ public function isDecorated(): bool; /** * Sets a new style. - * - * @return void */ - public function setStyle(string $name, OutputFormatterStyleInterface $style); + public function setStyle(string $name, OutputFormatterStyleInterface $style): void; /** * Checks if output formatter has style with specified name. diff --git a/Formatter/OutputFormatterStyle.php b/Formatter/OutputFormatterStyle.php index f075e881d..4582ccd05 100644 --- a/Formatter/OutputFormatterStyle.php +++ b/Formatter/OutputFormatterStyle.php @@ -38,18 +38,12 @@ public function __construct(string $foreground = null, string $background = null $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); } - /** - * @return void - */ - public function setForeground(?string $color) + public function setForeground(?string $color): void { $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); } - /** - * @return void - */ - public function setBackground(?string $color) + public function setBackground(?string $color): void { $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); } @@ -59,19 +53,13 @@ public function setHref(string $url): void $this->href = $url; } - /** - * @return void - */ - public function setOption(string $option) + public function setOption(string $option): void { $this->options[] = $option; $this->color = new Color($this->foreground, $this->background, $this->options); } - /** - * @return void - */ - public function unsetOption(string $option) + public function unsetOption(string $option): void { $pos = array_search($option, $this->options); if (false !== $pos) { @@ -81,10 +69,7 @@ public function unsetOption(string $option) $this->color = new Color($this->foreground, $this->background, $this->options); } - /** - * @return void - */ - public function setOptions(array $options) + public function setOptions(array $options): void { $this->color = new Color($this->foreground, $this->background, $this->options = $options); } diff --git a/Formatter/OutputFormatterStyleInterface.php b/Formatter/OutputFormatterStyleInterface.php index 3b15098cb..037419277 100644 --- a/Formatter/OutputFormatterStyleInterface.php +++ b/Formatter/OutputFormatterStyleInterface.php @@ -20,38 +20,28 @@ interface OutputFormatterStyleInterface { /** * Sets style foreground color. - * - * @return void */ - public function setForeground(?string $color); + public function setForeground(?string $color): void; /** * Sets style background color. - * - * @return void */ - public function setBackground(?string $color); + public function setBackground(?string $color): void; /** * Sets some specific style option. - * - * @return void */ - public function setOption(string $option); + public function setOption(string $option): void; /** * Unsets some specific style option. - * - * @return void */ - public function unsetOption(string $option); + public function unsetOption(string $option): void; /** * Sets multiple style options at once. - * - * @return void */ - public function setOptions(array $options); + public function setOptions(array $options): void; /** * Applies the style to a given text. diff --git a/Formatter/OutputFormatterStyleStack.php b/Formatter/OutputFormatterStyleStack.php index f98c2eff7..c3726a35d 100644 --- a/Formatter/OutputFormatterStyleStack.php +++ b/Formatter/OutputFormatterStyleStack.php @@ -34,20 +34,16 @@ public function __construct(OutputFormatterStyleInterface $emptyStyle = null) /** * Resets stack (ie. empty internal arrays). - * - * @return void */ - public function reset() + public function reset(): void { $this->styles = []; } /** * Pushes a style in the stack. - * - * @return void */ - public function push(OutputFormatterStyleInterface $style) + public function push(OutputFormatterStyleInterface $style): void { $this->styles[] = $style; } diff --git a/Formatter/WrappableOutputFormatterInterface.php b/Formatter/WrappableOutputFormatterInterface.php index 746cd27e7..412d9976f 100644 --- a/Formatter/WrappableOutputFormatterInterface.php +++ b/Formatter/WrappableOutputFormatterInterface.php @@ -20,8 +20,6 @@ interface WrappableOutputFormatterInterface extends OutputFormatterInterface { /** * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping). - * - * @return string */ - public function formatAndWrap(?string $message, int $width); + public function formatAndWrap(?string $message, int $width): string; } diff --git a/Helper/DescriptorHelper.php b/Helper/DescriptorHelper.php index eb32bce8f..300c7b102 100644 --- a/Helper/DescriptorHelper.php +++ b/Helper/DescriptorHelper.php @@ -50,11 +50,9 @@ public function __construct() * * format: string, the output format name * * raw_text: boolean, sets output type as raw * - * @return void - * * @throws InvalidArgumentException when the given format is not supported */ - public function describe(OutputInterface $output, ?object $object, array $options = []) + public function describe(OutputInterface $output, ?object $object, array $options = []): void { $options = array_merge([ 'raw_text' => false, diff --git a/Helper/Helper.php b/Helper/Helper.php index c80c1f468..db0cd661d 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -23,10 +23,7 @@ abstract class Helper implements HelperInterface { protected $helperSet; - /** - * @return void - */ - public function setHelperSet(?HelperSet $helperSet) + public function setHelperSet(?HelperSet $helperSet): void { $this->helperSet = $helperSet; } @@ -88,10 +85,7 @@ public static function substr(?string $string, int $from, int $length = null): s return mb_substr($string, $from, $length, $encoding); } - /** - * @return string - */ - public static function formatTime(int|float $secs) + public static function formatTime(int|float $secs): string { static $timeFormats = [ [0, '< 1 sec'], @@ -120,10 +114,7 @@ public static function formatTime(int|float $secs) } } - /** - * @return string - */ - public static function formatMemory(int $memory) + public static function formatMemory(int $memory): string { if ($memory >= 1024 * 1024 * 1024) { return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); @@ -140,10 +131,7 @@ public static function formatMemory(int $memory) return sprintf('%d B', $memory); } - /** - * @return string - */ - public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) + public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string): string { $isDecorated = $formatter->isDecorated(); $formatter->setDecorated(false); diff --git a/Helper/HelperInterface.php b/Helper/HelperInterface.php index ab626c938..8c4da3c91 100644 --- a/Helper/HelperInterface.php +++ b/Helper/HelperInterface.php @@ -20,10 +20,8 @@ interface HelperInterface { /** * Sets the helper set associated with this helper. - * - * @return void */ - public function setHelperSet(?HelperSet $helperSet); + public function setHelperSet(?HelperSet $helperSet): void; /** * Gets the helper set associated with this helper. @@ -32,8 +30,6 @@ public function getHelperSet(): ?HelperSet; /** * Returns the canonical name of this helper. - * - * @return string */ - public function getName(); + public function getName(): string; } diff --git a/Helper/HelperSet.php b/Helper/HelperSet.php index dc5d499ca..42153b68d 100644 --- a/Helper/HelperSet.php +++ b/Helper/HelperSet.php @@ -35,10 +35,7 @@ public function __construct(array $helpers = []) } } - /** - * @return void - */ - public function set(HelperInterface $helper, string $alias = null) + public function set(HelperInterface $helper, string $alias = null): void { $this->helpers[$helper->getName()] = $helper; if (null !== $alias) { diff --git a/Helper/InputAwareHelper.php b/Helper/InputAwareHelper.php index 6f8225973..8e7ee52a5 100644 --- a/Helper/InputAwareHelper.php +++ b/Helper/InputAwareHelper.php @@ -23,10 +23,7 @@ abstract class InputAwareHelper extends Helper implements InputAwareInterface { protected $input; - /** - * @return void - */ - public function setInput(InputInterface $input) + public function setInput(InputInterface $input): void { $this->input = $input; } diff --git a/Helper/ProgressIndicator.php b/Helper/ProgressIndicator.php index 84dbef950..d5694c696 100644 --- a/Helper/ProgressIndicator.php +++ b/Helper/ProgressIndicator.php @@ -70,10 +70,8 @@ public function __construct(OutputInterface $output, string $format = null, int /** * Sets the current indicator message. - * - * @return void */ - public function setMessage(?string $message) + public function setMessage(?string $message): void { $this->message = $message; @@ -82,10 +80,8 @@ public function setMessage(?string $message) /** * Starts the indicator output. - * - * @return void */ - public function start(string $message) + public function start(string $message): void { if ($this->started) { throw new LogicException('Progress indicator already started.'); @@ -102,10 +98,8 @@ public function start(string $message) /** * Advances the indicator. - * - * @return void */ - public function advance() + public function advance(): void { if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); @@ -129,10 +123,8 @@ public function advance() /** * Finish the indicator with message. - * - * @return void */ - public function finish(string $message) + public function finish(string $message): void { if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); @@ -156,10 +148,8 @@ public static function getFormatDefinition(string $name): ?string * Sets a placeholder formatter for a given name. * * This method also allow you to override an existing placeholder. - * - * @return void */ - public static function setPlaceholderFormatterDefinition(string $name, callable $callable) + public static function setPlaceholderFormatterDefinition(string $name, callable $callable): void { self::$formatters ??= self::initPlaceholderFormatters(); diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index f32813c6c..cb75ac914 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -89,10 +89,8 @@ public function getName(): string /** * Prevents usage of stty. - * - * @return void */ - public static function disableStty() + public static function disableStty(): void { self::$stty = false; } @@ -190,10 +188,8 @@ private function getDefaultAnswer(Question $question): mixed /** * Outputs the question prompt. - * - * @return void */ - protected function writePrompt(OutputInterface $output, Question $question) + protected function writePrompt(OutputInterface $output, Question $question): void { $message = $question->getQuestion(); @@ -228,10 +224,8 @@ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string /** * Outputs an error message. - * - * @return void */ - protected function writeError(OutputInterface $output, \Exception $error) + protected function writeError(OutputInterface $output, \Exception $error): void { if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); diff --git a/Helper/SymfonyQuestionHelper.php b/Helper/SymfonyQuestionHelper.php index 8ebc84376..48d947b75 100644 --- a/Helper/SymfonyQuestionHelper.php +++ b/Helper/SymfonyQuestionHelper.php @@ -25,10 +25,7 @@ */ class SymfonyQuestionHelper extends QuestionHelper { - /** - * @return void - */ - protected function writePrompt(OutputInterface $output, Question $question) + protected function writePrompt(OutputInterface $output, Question $question): void { $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); $default = $question->getDefault(); @@ -83,10 +80,7 @@ protected function writePrompt(OutputInterface $output, Question $question) $output->write($prompt); } - /** - * @return void - */ - protected function writeError(OutputInterface $output, \Exception $error) + protected function writeError(OutputInterface $output, \Exception $error): void { if ($output instanceof SymfonyStyle) { $output->newLine(); diff --git a/Helper/Table.php b/Helper/Table.php index db238c0fb..ad034ec36 100644 --- a/Helper/Table.php +++ b/Helper/Table.php @@ -66,10 +66,8 @@ public function __construct(OutputInterface $output) /** * Sets a style definition. - * - * @return void */ - public static function setStyleDefinition(string $name, TableStyle $style) + public static function setStyleDefinition(string $name, TableStyle $style): void { self::$styles ??= self::initStyles(); @@ -194,7 +192,7 @@ public function setHeaders(array $headers): static /** * @return $this */ - public function setRows(array $rows) + public function setRows(array $rows): static { $this->rows = []; @@ -312,10 +310,8 @@ public function setVertical(bool $vertical = true): static * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | * +---------------+-----------------------+------------------+ - * - * @return void */ - public function render() + public function render(): void { $divider = new TableSeparator(); $isCellWithColspan = static fn ($cell) => $cell instanceof TableCell && $cell->getColspan() >= 2; diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index 59f9217ec..9ae2f54f5 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -55,18 +55,12 @@ public function __construct(array $argv = null, InputDefinition $definition = nu parent::__construct($definition); } - /** - * @return void - */ - protected function setTokens(array $tokens) + protected function setTokens(array $tokens): void { $this->tokens = $tokens; } - /** - * @return void - */ - protected function parse() + protected function parse(): void { $parseOptions = true; $this->parsed = $this->tokens; diff --git a/Input/ArrayInput.php b/Input/ArrayInput.php index 355de61dd..03b200b13 100644 --- a/Input/ArrayInput.php +++ b/Input/ArrayInput.php @@ -113,10 +113,7 @@ public function __toString(): string return implode(' ', $params); } - /** - * @return void - */ - protected function parse() + protected function parse(): void { foreach ($this->parameters as $key => $value) { if ('--' === $key) { diff --git a/Input/Input.php b/Input/Input.php index 0f5617cd1..0a8c90654 100644 --- a/Input/Input.php +++ b/Input/Input.php @@ -43,10 +43,7 @@ public function __construct(InputDefinition $definition = null) } } - /** - * @return void - */ - public function bind(InputDefinition $definition) + public function bind(InputDefinition $definition): void { $this->arguments = []; $this->options = []; @@ -57,15 +54,10 @@ public function bind(InputDefinition $definition) /** * Processes command line arguments. - * - * @return void */ - abstract protected function parse(); + abstract protected function parse(): void; - /** - * @return void - */ - public function validate() + public function validate(): void { $definition = $this->definition; $givenArguments = $this->arguments; @@ -82,10 +74,7 @@ public function isInteractive(): bool return $this->interactive; } - /** - * @return void - */ - public function setInteractive(bool $interactive) + public function setInteractive(bool $interactive): void { $this->interactive = $interactive; } @@ -104,10 +93,7 @@ public function getArgument(string $name): mixed return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); } - /** - * @return void - */ - public function setArgument(string $name, mixed $value) + public function setArgument(string $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); @@ -143,10 +129,7 @@ public function getOption(string $name): mixed return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } - /** - * @return void - */ - public function setOption(string $name, mixed $value) + public function setOption(string $name, mixed $value): void { if ($this->definition->hasNegation($name)) { $this->options[$this->definition->negationToName($name)] = !$value; @@ -174,10 +157,8 @@ public function escapeToken(string $token): string /** * @param resource $stream - * - * @return void */ - public function setStream($stream) + public function setStream($stream): void { $this->stream = $stream; } diff --git a/Input/InputArgument.php b/Input/InputArgument.php index fa57f5d0d..642ae6600 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -91,11 +91,9 @@ public function isArray(): bool /** * Sets the default value. * - * @return void - * * @throws LogicException When incorrect default value is given */ - public function setDefault(string|bool|int|float|array|null $default) + public function setDefault(string|bool|int|float|array|null $default): void { if ($this->isRequired() && null !== $default) { throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); diff --git a/Input/InputAwareInterface.php b/Input/InputAwareInterface.php index 0ad27b455..ba4664cdb 100644 --- a/Input/InputAwareInterface.php +++ b/Input/InputAwareInterface.php @@ -21,8 +21,6 @@ interface InputAwareInterface { /** * Sets the Console Input. - * - * @return void */ - public function setInput(InputInterface $input); + public function setInput(InputInterface $input): void; } diff --git a/Input/InputDefinition.php b/Input/InputDefinition.php index b7162d770..f27e29748 100644 --- a/Input/InputDefinition.php +++ b/Input/InputDefinition.php @@ -46,10 +46,8 @@ public function __construct(array $definition = []) /** * Sets the definition of the input. - * - * @return void */ - public function setDefinition(array $definition) + public function setDefinition(array $definition): void { $arguments = []; $options = []; @@ -69,10 +67,8 @@ public function setDefinition(array $definition) * Sets the InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects - * - * @return void */ - public function setArguments(array $arguments = []) + public function setArguments(array $arguments = []): void { $this->arguments = []; $this->requiredCount = 0; @@ -85,10 +81,8 @@ public function setArguments(array $arguments = []) * Adds an array of InputArgument objects. * * @param InputArgument[] $arguments An array of InputArgument objects - * - * @return void */ - public function addArguments(?array $arguments = []) + public function addArguments(?array $arguments = []): void { if (null !== $arguments) { foreach ($arguments as $argument) { @@ -98,11 +92,9 @@ public function addArguments(?array $arguments = []) } /** - * @return void - * * @throws LogicException When incorrect argument is given */ - public function addArgument(InputArgument $argument) + public function addArgument(InputArgument $argument): void { if (isset($this->arguments[$argument->getName()])) { throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); @@ -198,10 +190,8 @@ public function getArgumentDefaults(): array * Sets the InputOption objects. * * @param InputOption[] $options An array of InputOption objects - * - * @return void */ - public function setOptions(array $options = []) + public function setOptions(array $options = []): void { $this->options = []; $this->shortcuts = []; @@ -213,10 +203,8 @@ public function setOptions(array $options = []) * Adds an array of InputOption objects. * * @param InputOption[] $options An array of InputOption objects - * - * @return void */ - public function addOptions(array $options = []) + public function addOptions(array $options = []): void { foreach ($options as $option) { $this->addOption($option); @@ -224,11 +212,9 @@ public function addOptions(array $options = []) } /** - * @return void - * * @throws LogicException When option given already exist */ - public function addOption(InputOption $option) + public function addOption(InputOption $option): void { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); diff --git a/Input/InputInterface.php b/Input/InputInterface.php index ca22bdbba..c177d960b 100644 --- a/Input/InputInterface.php +++ b/Input/InputInterface.php @@ -50,28 +50,22 @@ public function hasParameterOption(string|array $values, bool $onlyParams = fals * @param string|array $values The value(s) to look for in the raw parameters (can be an array) * @param string|bool|int|float|array|null $default The default value to return if no result is found * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal - * - * @return mixed */ - public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false); + public function getParameterOption(string|array $values, string|bool|int|float|array|null $default = false, bool $onlyParams = false): mixed; /** * Binds the current Input instance with the given arguments and options. * - * @return void - * * @throws RuntimeException */ - public function bind(InputDefinition $definition); + public function bind(InputDefinition $definition): void; /** * Validates the input. * - * @return void - * * @throws RuntimeException When not enough arguments are given */ - public function validate(); + public function validate(): void; /** * Returns all the given arguments merged with the default values. @@ -83,20 +77,16 @@ public function getArguments(): array; /** * Returns the argument value for a given argument name. * - * @return mixed - * * @throws InvalidArgumentException When argument given doesn't exist */ - public function getArgument(string $name); + public function getArgument(string $name): mixed; /** * Sets an argument value by name. * - * @return void - * * @throws InvalidArgumentException When argument given doesn't exist */ - public function setArgument(string $name, mixed $value); + public function setArgument(string $name, mixed $value): void; /** * Returns true if an InputArgument object exists by name or position. @@ -113,20 +103,16 @@ public function getOptions(): array; /** * Returns the option value for a given option name. * - * @return mixed - * * @throws InvalidArgumentException When option given doesn't exist */ - public function getOption(string $name); + public function getOption(string $name): mixed; /** * Sets an option value by name. * - * @return void - * * @throws InvalidArgumentException When option given doesn't exist */ - public function setOption(string $name, mixed $value); + public function setOption(string $name, mixed $value): void; /** * Returns true if an InputOption object exists by name. @@ -140,10 +126,8 @@ public function isInteractive(): bool; /** * Sets the input interactivity. - * - * @return void */ - public function setInteractive(bool $interactive); + public function setInteractive(bool $interactive): void; /** * Returns a stringified representation of the args passed to the command. diff --git a/Input/InputOption.php b/Input/InputOption.php index c9e8aa82b..f8e9b0dd6 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -178,10 +178,7 @@ public function isNegatable(): bool return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } - /** - * @return void - */ - public function setDefault(string|bool|int|float|array|null $default) + public function setDefault(string|bool|int|float|array|null $default): void { if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); diff --git a/Input/StreamableInputInterface.php b/Input/StreamableInputInterface.php index 4b95fcb11..4a0dc017f 100644 --- a/Input/StreamableInputInterface.php +++ b/Input/StreamableInputInterface.php @@ -25,10 +25,8 @@ interface StreamableInputInterface extends InputInterface * This is mainly useful for testing purpose. * * @param resource $stream The input stream - * - * @return void */ - public function setStream($stream); + public function setStream($stream): void; /** * Returns the input stream. diff --git a/Output/BufferedOutput.php b/Output/BufferedOutput.php index ef5099bfd..3c8d3906f 100644 --- a/Output/BufferedOutput.php +++ b/Output/BufferedOutput.php @@ -29,10 +29,7 @@ public function fetch(): string return $content; } - /** - * @return void - */ - protected function doWrite(string $message, bool $newline) + protected function doWrite(string $message, bool $newline): void { $this->buffer .= $message; diff --git a/Output/ConsoleOutput.php b/Output/ConsoleOutput.php index c1eb7cd14..f9e6c7710 100644 --- a/Output/ConsoleOutput.php +++ b/Output/ConsoleOutput.php @@ -64,28 +64,19 @@ public function section(): ConsoleSectionOutput return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); } - /** - * @return void - */ - public function setDecorated(bool $decorated) + public function setDecorated(bool $decorated): void { parent::setDecorated($decorated); $this->stderr->setDecorated($decorated); } - /** - * @return void - */ - public function setFormatter(OutputFormatterInterface $formatter) + public function setFormatter(OutputFormatterInterface $formatter): void { parent::setFormatter($formatter); $this->stderr->setFormatter($formatter); } - /** - * @return void - */ - public function setVerbosity(int $level) + public function setVerbosity(int $level): void { parent::setVerbosity($level); $this->stderr->setVerbosity($level); @@ -96,10 +87,7 @@ public function getErrorOutput(): OutputInterface return $this->stderr; } - /** - * @return void - */ - public function setErrorOutput(OutputInterface $error) + public function setErrorOutput(OutputInterface $error): void { $this->stderr = $error; } diff --git a/Output/ConsoleOutputInterface.php b/Output/ConsoleOutputInterface.php index 9c0049c8f..1f8f147ce 100644 --- a/Output/ConsoleOutputInterface.php +++ b/Output/ConsoleOutputInterface.php @@ -24,10 +24,7 @@ interface ConsoleOutputInterface extends OutputInterface */ public function getErrorOutput(): OutputInterface; - /** - * @return void - */ - public function setErrorOutput(OutputInterface $error); + public function setErrorOutput(OutputInterface $error): void; public function section(): ConsoleSectionOutput; } diff --git a/Output/ConsoleSectionOutput.php b/Output/ConsoleSectionOutput.php index 3f3f1434b..d3dbaa5a9 100644 --- a/Output/ConsoleSectionOutput.php +++ b/Output/ConsoleSectionOutput.php @@ -60,10 +60,8 @@ public function setMaxHeight(int $maxHeight): void * Clears previous output for this section. * * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared - * - * @return void */ - public function clear(int $lines = null) + public function clear(int $lines = null): void { if (empty($this->content) || !$this->isDecorated()) { return; @@ -83,10 +81,8 @@ public function clear(int $lines = null) /** * Overwrites the previous output with a new message. - * - * @return void */ - public function overwrite(string|iterable $message) + public function overwrite(string|iterable $message): void { $this->clear(); $this->writeln($message); @@ -163,10 +159,7 @@ public function addNewLineOfInputSubmit(): void ++$this->lines; } - /** - * @return void - */ - protected function doWrite(string $message, bool $newline) + protected function doWrite(string $message, bool $newline): void { if (!$this->isDecorated()) { parent::doWrite($message, $newline); diff --git a/Output/NullOutput.php b/Output/NullOutput.php index f3aa15b1d..40ae33282 100644 --- a/Output/NullOutput.php +++ b/Output/NullOutput.php @@ -26,10 +26,7 @@ class NullOutput implements OutputInterface { private NullOutputFormatter $formatter; - /** - * @return void - */ - public function setFormatter(OutputFormatterInterface $formatter) + public function setFormatter(OutputFormatterInterface $formatter): void { // do nothing } @@ -40,10 +37,7 @@ public function getFormatter(): OutputFormatterInterface return $this->formatter ??= new NullOutputFormatter(); } - /** - * @return void - */ - public function setDecorated(bool $decorated) + public function setDecorated(bool $decorated): void { // do nothing } @@ -53,10 +47,7 @@ public function isDecorated(): bool return false; } - /** - * @return void - */ - public function setVerbosity(int $level) + public function setVerbosity(int $level): void { // do nothing } @@ -86,18 +77,12 @@ public function isDebug(): bool return false; } - /** - * @return void - */ - public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) + public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL): void { // do nothing } - /** - * @return void - */ - public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) + public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL): void { // do nothing } diff --git a/Output/Output.php b/Output/Output.php index 3a06311a8..fe8564bb9 100644 --- a/Output/Output.php +++ b/Output/Output.php @@ -44,10 +44,7 @@ public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $deco $this->formatter->setDecorated($decorated); } - /** - * @return void - */ - public function setFormatter(OutputFormatterInterface $formatter) + public function setFormatter(OutputFormatterInterface $formatter): void { $this->formatter = $formatter; } @@ -57,10 +54,7 @@ public function getFormatter(): OutputFormatterInterface return $this->formatter; } - /** - * @return void - */ - public function setDecorated(bool $decorated) + public function setDecorated(bool $decorated): void { $this->formatter->setDecorated($decorated); } @@ -70,10 +64,7 @@ public function isDecorated(): bool return $this->formatter->isDecorated(); } - /** - * @return void - */ - public function setVerbosity(int $level) + public function setVerbosity(int $level): void { $this->verbosity = $level; } @@ -103,18 +94,12 @@ public function isDebug(): bool return self::VERBOSITY_DEBUG <= $this->verbosity; } - /** - * @return void - */ - public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL) + public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL): void { $this->write($messages, true, $options); } - /** - * @return void - */ - public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL) + public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL): void { if (!is_iterable($messages)) { $messages = [$messages]; @@ -148,8 +133,6 @@ public function write(string|iterable $messages, bool $newline = false, int $opt /** * Writes a message to the output. - * - * @return void */ - abstract protected function doWrite(string $message, bool $newline); + abstract protected function doWrite(string $message, bool $newline): void; } diff --git a/Output/OutputInterface.php b/Output/OutputInterface.php index 19a817901..41315fbf2 100644 --- a/Output/OutputInterface.php +++ b/Output/OutputInterface.php @@ -36,29 +36,23 @@ interface OutputInterface * @param bool $newline Whether to add a newline * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL - * - * @return void */ - public function write(string|iterable $messages, bool $newline = false, int $options = 0); + public function write(string|iterable $messages, bool $newline = false, int $options = 0): void; /** * Writes a message to the output and adds a newline at the end. * * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL - * - * @return void */ - public function writeln(string|iterable $messages, int $options = 0); + public function writeln(string|iterable $messages, int $options = 0): void; /** * Sets the verbosity of the output. * * @param self::VERBOSITY_* $level - * - * @return void */ - public function setVerbosity(int $level); + public function setVerbosity(int $level): void; /** * Gets the current verbosity of the output. @@ -89,20 +83,15 @@ public function isDebug(): bool; /** * Sets the decorated flag. - * - * @return void */ - public function setDecorated(bool $decorated); + public function setDecorated(bool $decorated): void; /** * Gets the decorated flag. */ public function isDecorated(): bool; - /** - * @return void - */ - public function setFormatter(OutputFormatterInterface $formatter); + public function setFormatter(OutputFormatterInterface $formatter): void; /** * Returns current output formatter instance. diff --git a/Output/StreamOutput.php b/Output/StreamOutput.php index 155066ea0..1942f8aee 100644 --- a/Output/StreamOutput.php +++ b/Output/StreamOutput.php @@ -62,10 +62,7 @@ public function getStream() return $this->stream; } - /** - * @return void - */ - protected function doWrite(string $message, bool $newline) + protected function doWrite(string $message, bool $newline): void { if ($newline) { $message .= \PHP_EOL; diff --git a/Output/TrimmedBufferOutput.php b/Output/TrimmedBufferOutput.php index b00445ece..5655e7bc8 100644 --- a/Output/TrimmedBufferOutput.php +++ b/Output/TrimmedBufferOutput.php @@ -45,10 +45,7 @@ public function fetch(): string return $content; } - /** - * @return void - */ - protected function doWrite(string $message, bool $newline) + protected function doWrite(string $message, bool $newline): void { $this->buffer .= $message; diff --git a/Question/Question.php b/Question/Question.php index dec0954e7..c79683cd5 100644 --- a/Question/Question.php +++ b/Question/Question.php @@ -260,10 +260,7 @@ public function getNormalizer(): ?callable return $this->normalizer; } - /** - * @return bool - */ - protected function isAssoc(array $array) + protected function isAssoc(array $array): bool { return (bool) \count(array_filter(array_keys($array), 'is_string')); } diff --git a/Style/OutputStyle.php b/Style/OutputStyle.php index ddfa8decc..05076c00f 100644 --- a/Style/OutputStyle.php +++ b/Style/OutputStyle.php @@ -30,10 +30,7 @@ public function __construct(OutputInterface $output) $this->output = $output; } - /** - * @return void - */ - public function newLine(int $count = 1) + public function newLine(int $count = 1): void { $this->output->write(str_repeat(\PHP_EOL, $count)); } @@ -43,26 +40,17 @@ public function createProgressBar(int $max = 0): ProgressBar return new ProgressBar($this->output, $max); } - /** - * @return void - */ - public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) + public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL): void { $this->output->write($messages, $newline, $type); } - /** - * @return void - */ - public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) + public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL): void { $this->output->writeln($messages, $type); } - /** - * @return void - */ - public function setVerbosity(int $level) + public function setVerbosity(int $level): void { $this->output->setVerbosity($level); } @@ -72,10 +60,7 @@ public function getVerbosity(): int return $this->output->getVerbosity(); } - /** - * @return void - */ - public function setDecorated(bool $decorated) + public function setDecorated(bool $decorated): void { $this->output->setDecorated($decorated); } @@ -85,10 +70,7 @@ public function isDecorated(): bool return $this->output->isDecorated(); } - /** - * @return void - */ - public function setFormatter(OutputFormatterInterface $formatter) + public function setFormatter(OutputFormatterInterface $formatter): void { $this->output->setFormatter($formatter); } @@ -118,10 +100,7 @@ public function isDebug(): bool return $this->output->isDebug(); } - /** - * @return OutputInterface - */ - protected function getErrorOutput() + protected function getErrorOutput(): OutputInterface { if (!$this->output instanceof ConsoleOutputInterface) { return $this->output; diff --git a/Style/StyleInterface.php b/Style/StyleInterface.php index e25a65bd2..869b16090 100644 --- a/Style/StyleInterface.php +++ b/Style/StyleInterface.php @@ -20,73 +20,53 @@ interface StyleInterface { /** * Formats a command title. - * - * @return void */ - public function title(string $message); + public function title(string $message): void; /** * Formats a section title. - * - * @return void */ - public function section(string $message); + public function section(string $message): void; /** * Formats a list. - * - * @return void */ - public function listing(array $elements); + public function listing(array $elements): void; /** * Formats informational text. - * - * @return void */ - public function text(string|array $message); + public function text(string|array $message): void; /** * Formats a success result bar. - * - * @return void */ - public function success(string|array $message); + public function success(string|array $message): void; /** * Formats an error result bar. - * - * @return void */ - public function error(string|array $message); + public function error(string|array $message): void; /** * Formats an warning result bar. - * - * @return void */ - public function warning(string|array $message); + public function warning(string|array $message): void; /** * Formats a note admonition. - * - * @return void */ - public function note(string|array $message); + public function note(string|array $message): void; /** * Formats a caution admonition. - * - * @return void */ - public function caution(string|array $message); + public function caution(string|array $message): void; /** * Formats a table. - * - * @return void */ - public function table(array $headers, array $rows); + public function table(array $headers, array $rows): void; /** * Asks a question. @@ -110,29 +90,21 @@ public function choice(string $question, array $choices, mixed $default = null): /** * Add newline(s). - * - * @return void */ - public function newLine(int $count = 1); + public function newLine(int $count = 1): void; /** * Starts the progress output. - * - * @return void */ - public function progressStart(int $max = 0); + public function progressStart(int $max = 0): void; /** * Advances the progress output X steps. - * - * @return void */ - public function progressAdvance(int $step = 1); + public function progressAdvance(int $step = 1): void; /** * Finishes the progress output. - * - * @return void */ - public function progressFinish(); + public function progressFinish(): void; } diff --git a/Style/SymfonyStyle.php b/Style/SymfonyStyle.php index cecce6c01..3fbdac956 100644 --- a/Style/SymfonyStyle.php +++ b/Style/SymfonyStyle.php @@ -60,10 +60,8 @@ public function __construct(InputInterface $input, OutputInterface $output) /** * Formats a message as a block of text. - * - * @return void */ - public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true) + public function block(string|array $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true): void { $messages = \is_array($messages) ? array_values($messages) : [$messages]; @@ -72,10 +70,7 @@ public function block(string|array $messages, string $type = null, string $style $this->newLine(); } - /** - * @return void - */ - public function title(string $message) + public function title(string $message): void { $this->autoPrependBlock(); $this->writeln([ @@ -85,10 +80,7 @@ public function title(string $message) $this->newLine(); } - /** - * @return void - */ - public function section(string $message) + public function section(string $message): void { $this->autoPrependBlock(); $this->writeln([ @@ -98,10 +90,7 @@ public function section(string $message) $this->newLine(); } - /** - * @return void - */ - public function listing(array $elements) + public function listing(array $elements): void { $this->autoPrependText(); $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); @@ -110,10 +99,7 @@ public function listing(array $elements) $this->newLine(); } - /** - * @return void - */ - public function text(string|array $message) + public function text(string|array $message): void { $this->autoPrependText(); @@ -125,68 +111,46 @@ public function text(string|array $message) /** * Formats a command comment. - * - * @return void */ - public function comment(string|array $message) + public function comment(string|array $message): void { $this->block($message, null, null, ' // ', false, false); } - /** - * @return void - */ - public function success(string|array $message) + public function success(string|array $message): void { $this->block($message, 'OK', 'fg=black;bg=green', ' ', true); } - /** - * @return void - */ - public function error(string|array $message) + public function error(string|array $message): void { $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); } - /** - * @return void - */ - public function warning(string|array $message) + public function warning(string|array $message): void { $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true); } - /** - * @return void - */ - public function note(string|array $message) + public function note(string|array $message): void { $this->block($message, 'NOTE', 'fg=yellow', ' ! '); } /** * Formats an info message. - * - * @return void */ - public function info(string|array $message) + public function info(string|array $message): void { $this->block($message, 'INFO', 'fg=green', ' ', true); } - /** - * @return void - */ - public function caution(string|array $message) + public function caution(string|array $message): void { $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); } - /** - * @return void - */ - public function table(array $headers, array $rows) + public function table(array $headers, array $rows): void { $this->createTable() ->setHeaders($headers) @@ -199,10 +163,8 @@ public function table(array $headers, array $rows) /** * Formats a horizontal table. - * - * @return void */ - public function horizontalTable(array $headers, array $rows) + public function horizontalTable(array $headers, array $rows): void { $this->createTable() ->setHorizontal(true) @@ -221,10 +183,8 @@ public function horizontalTable(array $headers, array $rows) * * 'A title' * * ['key' => 'value'] * * new TableSeparator() - * - * @return void */ - public function definitionList(string|array|TableSeparator ...$list) + public function definitionList(string|array|TableSeparator ...$list): void { $headers = []; $row = []; @@ -285,27 +245,18 @@ public function choice(string $question, array $choices, mixed $default = null, return $this->askQuestion($questionChoice); } - /** - * @return void - */ - public function progressStart(int $max = 0) + public function progressStart(int $max = 0): void { $this->progressBar = $this->createProgressBar($max); $this->progressBar->start(); } - /** - * @return void - */ - public function progressAdvance(int $step = 1) + public function progressAdvance(int $step = 1): void { $this->getProgressBar()->advance($step); } - /** - * @return void - */ - public function progressFinish() + public function progressFinish(): void { $this->getProgressBar()->finish(); $this->newLine(2); @@ -358,10 +309,7 @@ public function askQuestion(Question $question): mixed return $answer; } - /** - * @return void - */ - public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL) + public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORMAL): void { if (!is_iterable($messages)) { $messages = [$messages]; @@ -373,10 +321,7 @@ public function writeln(string|iterable $messages, int $type = self::OUTPUT_NORM } } - /** - * @return void - */ - public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL) + public function write(string|iterable $messages, bool $newline = false, int $type = self::OUTPUT_NORMAL): void { if (!is_iterable($messages)) { $messages = [$messages]; @@ -388,10 +333,7 @@ public function write(string|iterable $messages, bool $newline = false, int $typ } } - /** - * @return void - */ - public function newLine(int $count = 1) + public function newLine(int $count = 1): void { parent::newLine($count); $this->bufferedOutput->write(str_repeat("\n", $count)); diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index 229297c65..c058050be 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -74,7 +74,7 @@ protected function tearDown(): void if (9 === $i) { continue; } - pcntl_signal($i, SIG_DFL); + pcntl_signal($i, \SIG_DFL); } } } @@ -2049,7 +2049,7 @@ public function testSetSignalsToDispatchEvent() // And now we test without the blank handler $blankHandlerSignaled = false; - pcntl_signal(\SIGUSR1, SIG_DFL); + pcntl_signal(\SIGUSR1, \SIG_DFL); $application = $this->createSignalableApplication($command, $dispatcher); $application->setSignalsToDispatchEvent(\SIGUSR1); @@ -2312,7 +2312,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int for ($i = 0; $i <= 10 && $this->shouldContinue; ++$i) { $output->writeln('Still processing...'); - posix_kill(posix_getpid(), SIGINT); + posix_kill(posix_getpid(), \SIGINT); } $output->writeln('Wrapping up, wait a sec...'); diff --git a/Tests/ConsoleEventsTest.php b/Tests/ConsoleEventsTest.php index 78672a586..bb57b1fb1 100644 --- a/Tests/ConsoleEventsTest.php +++ b/Tests/ConsoleEventsTest.php @@ -39,7 +39,7 @@ protected function tearDown(): void if (9 === $i) { continue; } - pcntl_signal($i, SIG_DFL); + pcntl_signal($i, \SIG_DFL); } } } diff --git a/Tests/EventListener/ErrorListenerTest.php b/Tests/EventListener/ErrorListenerTest.php index 10bed7d03..e26109851 100644 --- a/Tests/EventListener/ErrorListenerTest.php +++ b/Tests/EventListener/ErrorListenerTest.php @@ -127,7 +127,7 @@ public function getParameterOption($values, $default = false, $onlyParams = fals { } - public function parse() + public function parse(): void { } diff --git a/Tests/Output/OutputTest.php b/Tests/Output/OutputTest.php index f337c4ddd..b7c0a98d9 100644 --- a/Tests/Output/OutputTest.php +++ b/Tests/Output/OutputTest.php @@ -182,7 +182,7 @@ public function clear() $this->output = ''; } - protected function doWrite(string $message, bool $newline) + protected function doWrite(string $message, bool $newline): void { $this->output .= $message.($newline ? "\n" : ''); } diff --git a/Tests/SignalRegistry/SignalRegistryTest.php b/Tests/SignalRegistry/SignalRegistryTest.php index f8bf03841..4cb435416 100644 --- a/Tests/SignalRegistry/SignalRegistryTest.php +++ b/Tests/SignalRegistry/SignalRegistryTest.php @@ -27,7 +27,7 @@ protected function tearDown(): void if (9 === $i) { continue; } - pcntl_signal($i, SIG_DFL); + pcntl_signal($i, \SIG_DFL); } } From 280bf763020308c394898911bc467c7e5ff20db0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 5 Jul 2023 15:32:22 +0200 Subject: [PATCH 06/59] [HttpKernel][Console] Revert native return types on Bundle and Command classes --- Command/Command.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Command/Command.php b/Command/Command.php index 017026e1e..c49891777 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -159,8 +159,10 @@ public function isEnabled(): bool /** * Configures the current command. + * + * @return void */ - protected function configure(): void + protected function configure() { } @@ -189,8 +191,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int * This method is executed before the InputDefinition is validated. * This means that this is the only place where the command can * interactively ask for values of missing required arguments. + * + * @return void */ - protected function interact(InputInterface $input, OutputInterface $output): void + protected function interact(InputInterface $input, OutputInterface $output) { } @@ -203,8 +207,10 @@ protected function interact(InputInterface $input, OutputInterface $output): voi * * @see InputInterface::bind() * @see InputInterface::validate() + * + * @return void */ - protected function initialize(InputInterface $input, OutputInterface $output): void + protected function initialize(InputInterface $input, OutputInterface $output) { } From bd8840e6fb840e3045e4d6c021ff370d40df71e5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 21 Jul 2023 15:36:26 +0200 Subject: [PATCH 07/59] Add types to public and protected properties --- Event/ConsoleEvent.php | 2 +- Helper/Helper.php | 2 +- Helper/InputAwareHelper.php | 2 +- Input/Input.php | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Event/ConsoleEvent.php b/Event/ConsoleEvent.php index 6ba1615fe..437a58e1e 100644 --- a/Event/ConsoleEvent.php +++ b/Event/ConsoleEvent.php @@ -23,7 +23,7 @@ */ class ConsoleEvent extends Event { - protected $command; + protected ?Command $command; private InputInterface $input; private OutputInterface $output; diff --git a/Helper/Helper.php b/Helper/Helper.php index db0cd661d..6b1365903 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -21,7 +21,7 @@ */ abstract class Helper implements HelperInterface { - protected $helperSet; + protected ?HelperSet $helperSet = null; public function setHelperSet(?HelperSet $helperSet): void { diff --git a/Helper/InputAwareHelper.php b/Helper/InputAwareHelper.php index 8e7ee52a5..47126bdaa 100644 --- a/Helper/InputAwareHelper.php +++ b/Helper/InputAwareHelper.php @@ -21,7 +21,7 @@ */ abstract class InputAwareHelper extends Helper implements InputAwareInterface { - protected $input; + protected InputInterface $input; public function setInput(InputInterface $input): void { diff --git a/Input/Input.php b/Input/Input.php index 740b1bc04..6a9248b7a 100644 --- a/Input/Input.php +++ b/Input/Input.php @@ -27,12 +27,12 @@ */ abstract class Input implements InputInterface, StreamableInputInterface { - protected $definition; + protected InputDefinition $definition; /** @var resource */ protected $stream; - protected $options = []; - protected $arguments = []; - protected $interactive = true; + protected array $options = []; + protected array $arguments = []; + protected bool $interactive = true; public function __construct(InputDefinition $definition = null) { From 235179850a9136f1acc79645038f4ce3f9c886ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 15 Nov 2023 23:01:24 +0100 Subject: [PATCH 08/59] Fix ProgressBar::iterate on empty iterator Co-authored-by: Florian Reimair --- Helper/ProgressBar.php | 59 +++++++++++++++++++++++--------- Tests/Helper/ProgressBarTest.php | 16 ++++++++- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index 64389c4a2..a1f806d5f 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -195,7 +195,7 @@ public function getStartTime(): int public function getMaxSteps(): int { - return $this->max; + return $this->max ?? 0; } public function getProgress(): int @@ -215,7 +215,7 @@ public function getProgressPercent(): float public function getBarOffset(): float { - return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); + return floor(null !== $this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); } public function getEstimated(): float @@ -253,7 +253,7 @@ public function setBarCharacter(string $char): void public function getBarCharacter(): string { - return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); + return $this->barChar ?? (null !== $this->max ? '=' : $this->emptyBarChar); } public function setEmptyBarCharacter(string $char): void @@ -315,7 +315,21 @@ public function maxSecondsBetweenRedraws(float $seconds): void */ public function iterate(iterable $iterable, int $max = null): iterable { - $this->start($max ?? (is_countable($iterable) ? \count($iterable) : 0)); + if (0 === $max) { + $max = null; + } + + $max ??= is_countable($iterable) ? \count($iterable) : null; + + if (0 === $max) { + $this->max = 0; + $this->stepWidth = 2; + $this->finish(); + + return; + } + + $this->start($max); foreach ($iterable as $key => $value) { yield $key => $value; @@ -373,11 +387,15 @@ public function setProgress(int $step): void $step = 0; } - $redrawFreq = $this->redrawFreq ?? (($this->max ?: 10) / 10); - $prevPeriod = (int) ($this->step / $redrawFreq); - $currPeriod = (int) ($step / $redrawFreq); + $redrawFreq = $this->redrawFreq ?? (($this->max ?? 10) / 10); + $prevPeriod = $redrawFreq ? (int) ($this->step / $redrawFreq) : 0; + $currPeriod = $redrawFreq ? (int) ($step / $redrawFreq) : 0; $this->step = $step; - $this->percent = $this->max ? (float) $this->step / $this->max : 0; + $this->percent = match ($this->max) { + null => 0, + 0 => 1, + default => (float) $this->step / $this->max, + }; $timeInterval = microtime(true) - $this->lastWriteTime; // Draw regardless of other limits @@ -398,11 +416,20 @@ public function setProgress(int $step): void } } - public function setMaxSteps(int $max): void + public function setMaxSteps(?int $max): void { + if (0 === $max) { + $max = null; + } + $this->format = null; - $this->max = max(0, $max); - $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4; + if (null === $max) { + $this->max = null; + $this->stepWidth = 4; + } else { + $this->max = max(0, $max); + $this->stepWidth = Helper::width((string) $this->max); + } } /** @@ -410,16 +437,16 @@ public function setMaxSteps(int $max): void */ public function finish(): void { - if (!$this->max) { + if (null === $this->max) { $this->max = $this->step; } - if ($this->step === $this->max && !$this->overwrite) { + if (($this->step === $this->max || null === $this->max) && !$this->overwrite) { // prevent double 100% output return; } - $this->setProgress($this->max); + $this->setProgress($this->max ?? $this->step); } /** @@ -542,14 +569,14 @@ private static function initPlaceholderFormatters(): array }, 'elapsed' => fn (self $bar) => Helper::formatTime(time() - $bar->getStartTime(), 2), 'remaining' => function (self $bar) { - if (!$bar->getMaxSteps()) { + if (null === $bar->getMaxSteps()) { throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); } return Helper::formatTime($bar->getRemaining(), 2); }, 'estimated' => function (self $bar) { - if (!$bar->getMaxSteps()) { + if (null === $bar->getMaxSteps()) { throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); } diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index 4dff078ae..cc7ed6c88 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -1092,6 +1092,20 @@ public function testIterateUncountable() ); } + public function testEmptyInputWithDebugFormat() + { + $bar = new ProgressBar($output = $this->getOutputStream()); + $bar->setFormat('%current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%'); + + $this->assertEquals([], iterator_to_array($bar->iterate([]))); + + rewind($output->getStream()); + $this->assertEquals( + ' 0/0 [============================] 100% < 1 sec/< 1 sec', + stream_get_contents($output->getStream()) + ); + } + protected function getOutputStream($decorated = true, $verbosity = StreamOutput::VERBOSITY_NORMAL) { return new StreamOutput(fopen('php://memory', 'r+', false), $verbosity, $decorated); @@ -1263,7 +1277,7 @@ public function testMultiLineFormatIsFullyCorrectlyWithManuallyCleanup() 'Foo!'.\PHP_EOL. $this->generateOutput('[--->------------------------]'). "\nProcessing \"foobar\"...". - $this->generateOutput("[----->----------------------]\nProcessing \"foobar\"..."), + $this->generateOutput("[============================]\nProcessing \"foobar\"..."), stream_get_contents($output->getStream()) ); } From 531f11d95b6c89815c37d446ff63d630ab9c9977 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 20 Nov 2023 19:32:45 +0100 Subject: [PATCH 09/59] [CssSelector][Serializer][Translation] [Command] Clean unused code --- Command/Command.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Command/Command.php b/Command/Command.php index c49891777..ef1e7c31e 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -277,10 +277,6 @@ public function run(InputInterface $input, OutputInterface $output): int $statusCode = ($this->code)($input, $output); } else { $statusCode = $this->execute($input, $output); - - if (!\is_int($statusCode)) { - throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); - } } return is_numeric($statusCode) ? (int) $statusCode : 0; From 0b33220c25d174123c4582f23b3d35625ae881a0 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 14 Dec 2023 11:03:37 +0100 Subject: [PATCH 10/59] Set `strict` parameter of `in_array` to true where possible --- Application.php | 2 +- Descriptor/ReStructuredTextDescriptor.php | 2 +- Helper/TableCellStyle.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Application.php b/Application.php index 07cc6d674..4d1a6d953 100644 --- a/Application.php +++ b/Application.php @@ -716,7 +716,7 @@ public function find(string $name): Command $aliases[$nameOrAlias] = $commandName; - return $commandName === $nameOrAlias || !\in_array($commandName, $commands); + return $commandName === $nameOrAlias || !\in_array($commandName, $commands, true); })); } diff --git a/Descriptor/ReStructuredTextDescriptor.php b/Descriptor/ReStructuredTextDescriptor.php index d4423fd34..f12fecb67 100644 --- a/Descriptor/ReStructuredTextDescriptor.php +++ b/Descriptor/ReStructuredTextDescriptor.php @@ -226,7 +226,7 @@ private function getNonDefaultOptions(InputDefinition $definition): array $nonDefaultOptions = []; foreach ($definition->getOptions() as $option) { // Skip global options. - if (!\in_array($option->getName(), $globalOptions)) { + if (!\in_array($option->getName(), $globalOptions, true)) { $nonDefaultOptions[] = $option; } } diff --git a/Helper/TableCellStyle.php b/Helper/TableCellStyle.php index 9419dcb40..49b97f853 100644 --- a/Helper/TableCellStyle.php +++ b/Helper/TableCellStyle.php @@ -67,7 +67,7 @@ public function getTagOptions(): array { return array_filter( $this->getOptions(), - fn ($key) => \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]), + fn ($key) => \in_array($key, self::TAG_OPTIONS, true) && isset($this->options[$key]), \ARRAY_FILTER_USE_KEY ); } From e6bafc780aad05f332917caa3f7b7576a1e05ef2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 18 Dec 2023 08:46:12 +0100 Subject: [PATCH 11/59] Code updates --- Helper/Table.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Helper/Table.php b/Helper/Table.php index fe2ac87c1..fd2e94d5d 100644 --- a/Helper/Table.php +++ b/Helper/Table.php @@ -717,7 +717,7 @@ private function fillNextRows(array $rows, int $line): array foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { // we need to know if $unmergedRow will be merged or inserted into $rows - if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) { + if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRow) <= $this->numberOfColumns)) { foreach ($unmergedRow as $cellKey => $cell) { // insert cell into row at cellKey position array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); @@ -726,7 +726,7 @@ private function fillNextRows(array $rows, int $line): array $row = $this->copyRow($rows, $unmergedRowKey - 1); foreach ($unmergedRow as $column => $cell) { if (!empty($cell)) { - $row[$column] = $unmergedRow[$column]; + $row[$column] = $cell; } } array_splice($rows, $unmergedRowKey, 0, [$row]); From e0b2ccdd08585175012a8a9999d842153835df78 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 10 Oct 2023 16:04:32 +0200 Subject: [PATCH 12/59] [Console][EventDispatcher][Security][Serializer][Workflow] Add PHPDoc to attribute classes and properties --- Attribute/AsCommand.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Attribute/AsCommand.php b/Attribute/AsCommand.php index b337f548f..6066d7c53 100644 --- a/Attribute/AsCommand.php +++ b/Attribute/AsCommand.php @@ -17,6 +17,12 @@ #[\Attribute(\Attribute::TARGET_CLASS)] class AsCommand { + /** + * @param string $name The name of the command, used when calling it (i.e. "cache:clear") + * @param string|null $description The description of the command, displayed with the help page + * @param string[] $aliases The list of aliases of the command. The command will be executed when using one of them (i.e. "cache:clean") + * @param bool $hidden If true, the command won't be shown when listing all the available commands, but it can still be run as any other command + */ public function __construct( public string $name, public ?string $description = null, From f92fef1127ac0222ab92dd09122ad6b324610785 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Tue, 2 Jan 2024 15:49:33 +0100 Subject: [PATCH 13/59] CS: trailing commas --- Completion/Suggestion.php | 2 +- Helper/OutputWrapper.php | 2 +- Output/AnsiColorMode.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Completion/Suggestion.php b/Completion/Suggestion.php index 7392965a2..3251b079f 100644 --- a/Completion/Suggestion.php +++ b/Completion/Suggestion.php @@ -20,7 +20,7 @@ class Suggestion implements \Stringable { public function __construct( private readonly string $value, - private readonly string $description = '' + private readonly string $description = '', ) { } diff --git a/Helper/OutputWrapper.php b/Helper/OutputWrapper.php index 2ec819c74..0ea2b7056 100644 --- a/Helper/OutputWrapper.php +++ b/Helper/OutputWrapper.php @@ -49,7 +49,7 @@ final class OutputWrapper private const URL_PATTERN = 'https?://\S+'; public function __construct( - private bool $allowCutUrls = false + private bool $allowCutUrls = false, ) { } diff --git a/Output/AnsiColorMode.php b/Output/AnsiColorMode.php index 5f9f744fe..ca40ffb79 100644 --- a/Output/AnsiColorMode.php +++ b/Output/AnsiColorMode.php @@ -63,7 +63,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string return match ($this) { self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), - self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b) + self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b), }; } @@ -72,7 +72,7 @@ private function convertFromRGB(int $r, int $g, int $b): int return match ($this) { self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b), self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b), - default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}.") + default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."), }; } From 7739bb6aef4a98d2a28465de5a5e2a78f66caa7a Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 2 Jan 2024 14:14:18 +0100 Subject: [PATCH 14/59] [Asset][BrowserKit][Cache][Console][CssSelector] Use CPP --- Application.php | 10 ++++------ Command/LazyCommand.php | 12 ++++++++---- CommandLoader/ContainerCommandLoader.php | 11 ++++------- CommandLoader/FactoryCommandLoader.php | 8 +++----- Cursor.php | 8 ++++---- Descriptor/ApplicationDescription.php | 13 +++++-------- Event/ConsoleErrorEvent.php | 11 ++++++----- Event/ConsoleEvent.php | 15 +++++---------- Event/ConsoleSignalEvent.php | 14 +++++++------- EventListener/ErrorListener.php | 8 +++----- Exception/CommandNotFoundException.php | 12 ++++++------ Helper/Dumper.php | 14 +++++--------- Helper/ProgressIndicator.php | 12 ++++++------ Helper/Table.php | 8 +++----- Helper/TableCell.php | 9 ++++----- Helper/TableRows.php | 8 +++----- Input/ArrayInput.php | 10 ++++------ Input/InputArgument.php | 15 +++++++-------- Input/InputOption.php | 14 ++++++++------ Logger/ConsoleLogger.php | 9 +++++---- Messenger/RunCommandMessageHandler.php | 5 +++-- Question/ChoiceQuestion.php | 9 +++++---- Question/ConfirmationQuestion.php | 10 +++++----- Question/Question.php | 10 ++++------ Style/OutputStyle.php | 8 +++----- Style/SymfonyStyle.php | 11 +++++------ Tester/ApplicationTester.php | 8 +++----- Tester/CommandCompletionTester.php | 8 +++----- Tester/CommandTester.php | 8 +++----- 29 files changed, 134 insertions(+), 164 deletions(-) diff --git a/Application.php b/Application.php index 4d1a6d953..00acef1dd 100644 --- a/Application.php +++ b/Application.php @@ -75,8 +75,6 @@ class Application implements ResetInterface private array $commands = []; private bool $wantHelps = false; private ?Command $runningCommand = null; - private string $name; - private string $version; private ?CommandLoaderInterface $commandLoader = null; private bool $catchExceptions = true; private bool $catchErrors = false; @@ -91,10 +89,10 @@ class Application implements ResetInterface private ?SignalRegistry $signalRegistry = null; private array $signalsToDispatchEvent = []; - public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN') - { - $this->name = $name; - $this->version = $version; + public function __construct( + private string $name = 'UNKNOWN', + private string $version = 'UNKNOWN', + ) { $this->terminal = new Terminal(); $this->defaultCommand = 'list'; if (\defined('SIGINT') && SignalRegistry::isSupported()) { diff --git a/Command/LazyCommand.php b/Command/LazyCommand.php index 7279724a6..df44b3d01 100644 --- a/Command/LazyCommand.php +++ b/Command/LazyCommand.php @@ -27,17 +27,21 @@ final class LazyCommand extends Command { private \Closure|Command $command; - private ?bool $isEnabled; - public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = true) - { + public function __construct( + string $name, + array $aliases, + string $description, + bool $isHidden, + \Closure $commandFactory, + private ?bool $isEnabled = true, + ) { $this->setName($name) ->setAliases($aliases) ->setHidden($isHidden) ->setDescription($description); $this->command = $commandFactory; - $this->isEnabled = $isEnabled; } public function ignoreValidationErrors(): void diff --git a/CommandLoader/ContainerCommandLoader.php b/CommandLoader/ContainerCommandLoader.php index bfa0ac467..84e25be76 100644 --- a/CommandLoader/ContainerCommandLoader.php +++ b/CommandLoader/ContainerCommandLoader.php @@ -22,16 +22,13 @@ */ class ContainerCommandLoader implements CommandLoaderInterface { - private ContainerInterface $container; - private array $commandMap; - /** * @param array $commandMap An array with command names as keys and service ids as values */ - public function __construct(ContainerInterface $container, array $commandMap) - { - $this->container = $container; - $this->commandMap = $commandMap; + public function __construct( + private ContainerInterface $container, + private array $commandMap, + ) { } public function get(string $name): Command diff --git a/CommandLoader/FactoryCommandLoader.php b/CommandLoader/FactoryCommandLoader.php index 9ced75aeb..ae16bf6f1 100644 --- a/CommandLoader/FactoryCommandLoader.php +++ b/CommandLoader/FactoryCommandLoader.php @@ -21,14 +21,12 @@ */ class FactoryCommandLoader implements CommandLoaderInterface { - private array $factories; - /** * @param callable[] $factories Indexed by command names */ - public function __construct(array $factories) - { - $this->factories = $factories; + public function __construct( + private array $factories, + ) { } public function has(string $name): bool diff --git a/Cursor.php b/Cursor.php index 69fd3821c..965f996e0 100644 --- a/Cursor.php +++ b/Cursor.php @@ -18,16 +18,16 @@ */ final class Cursor { - private OutputInterface $output; /** @var resource */ private $input; /** * @param resource|null $input */ - public function __construct(OutputInterface $output, $input = null) - { - $this->output = $output; + public function __construct( + private OutputInterface $output, + $input = null, + ) { $this->input = $input ?? (\defined('STDIN') ? \STDIN : fopen('php://input', 'r+')); } diff --git a/Descriptor/ApplicationDescription.php b/Descriptor/ApplicationDescription.php index f8ed18045..5149fde4c 100644 --- a/Descriptor/ApplicationDescription.php +++ b/Descriptor/ApplicationDescription.php @@ -24,9 +24,6 @@ class ApplicationDescription { public const GLOBAL_NAMESPACE = '_global'; - private Application $application; - private ?string $namespace; - private bool $showHidden; private array $namespaces; /** @@ -39,11 +36,11 @@ class ApplicationDescription */ private array $aliases = []; - public function __construct(Application $application, string $namespace = null, bool $showHidden = false) - { - $this->application = $application; - $this->namespace = $namespace; - $this->showHidden = $showHidden; + public function __construct( + private Application $application, + private ?string $namespace = null, + private bool $showHidden = false, + ) { } public function getNamespaces(): array diff --git a/Event/ConsoleErrorEvent.php b/Event/ConsoleErrorEvent.php index d4a691216..f469fbcee 100644 --- a/Event/ConsoleErrorEvent.php +++ b/Event/ConsoleErrorEvent.php @@ -22,14 +22,15 @@ */ final class ConsoleErrorEvent extends ConsoleEvent { - private \Throwable $error; private int $exitCode; - public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null) - { + public function __construct( + InputInterface $input, + OutputInterface $output, + private \Throwable $error, + Command $command = null, + ) { parent::__construct($command, $input, $output); - - $this->error = $error; } public function getError(): \Throwable diff --git a/Event/ConsoleEvent.php b/Event/ConsoleEvent.php index 437a58e1e..2f9f0778e 100644 --- a/Event/ConsoleEvent.php +++ b/Event/ConsoleEvent.php @@ -23,16 +23,11 @@ */ class ConsoleEvent extends Event { - protected ?Command $command; - - private InputInterface $input; - private OutputInterface $output; - - public function __construct(?Command $command, InputInterface $input, OutputInterface $output) - { - $this->command = $command; - $this->input = $input; - $this->output = $output; + public function __construct( + protected ?Command $command, + private InputInterface $input, + private OutputInterface $output, + ) { } /** diff --git a/Event/ConsoleSignalEvent.php b/Event/ConsoleSignalEvent.php index 95af1f915..b27f08a18 100644 --- a/Event/ConsoleSignalEvent.php +++ b/Event/ConsoleSignalEvent.php @@ -20,14 +20,14 @@ */ final class ConsoleSignalEvent extends ConsoleEvent { - private int $handlingSignal; - private int|false $exitCode; - - public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, int|false $exitCode = 0) - { + public function __construct( + Command $command, + InputInterface $input, + OutputInterface $output, + private int $handlingSignal, + private int|false $exitCode = 0, + ) { parent::__construct($command, $input, $output); - $this->handlingSignal = $handlingSignal; - $this->exitCode = $exitCode; } public function getHandlingSignal(): int diff --git a/EventListener/ErrorListener.php b/EventListener/ErrorListener.php index 5c38e8ef8..49915a498 100644 --- a/EventListener/ErrorListener.php +++ b/EventListener/ErrorListener.php @@ -24,11 +24,9 @@ */ class ErrorListener implements EventSubscriberInterface { - private ?LoggerInterface $logger; - - public function __construct(LoggerInterface $logger = null) - { - $this->logger = $logger; + public function __construct( + private ?LoggerInterface $logger = null, + ) { } public function onConsoleError(ConsoleErrorEvent $event): void diff --git a/Exception/CommandNotFoundException.php b/Exception/CommandNotFoundException.php index 1e9f1c793..47750d5f9 100644 --- a/Exception/CommandNotFoundException.php +++ b/Exception/CommandNotFoundException.php @@ -18,19 +18,19 @@ */ class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface { - private array $alternatives; - /** * @param string $message Exception message to throw * @param string[] $alternatives List of similar defined names * @param int $code Exception code * @param \Throwable|null $previous Previous exception used for the exception chaining */ - public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null) - { + public function __construct( + string $message, + private array $alternatives = [], + int $code = 0, + \Throwable $previous = null, + ) { parent::__construct($message, $code, $previous); - - $this->alternatives = $alternatives; } /** diff --git a/Helper/Dumper.php b/Helper/Dumper.php index 8c6a94d51..0cd01e616 100644 --- a/Helper/Dumper.php +++ b/Helper/Dumper.php @@ -21,17 +21,13 @@ */ final class Dumper { - private OutputInterface $output; - private ?CliDumper $dumper; - private ?ClonerInterface $cloner; private \Closure $handler; - public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null) - { - $this->output = $output; - $this->dumper = $dumper; - $this->cloner = $cloner; - + public function __construct( + private OutputInterface $output, + private ?CliDumper $dumper = null, + private ?ClonerInterface $cloner = null, + ) { if (class_exists(CliDumper::class)) { $this->handler = function ($var): string { $dumper = $this->dumper ??= new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR); diff --git a/Helper/ProgressIndicator.php b/Helper/ProgressIndicator.php index 8865ecc34..8ebf99145 100644 --- a/Helper/ProgressIndicator.php +++ b/Helper/ProgressIndicator.php @@ -31,13 +31,11 @@ class ProgressIndicator 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)', ]; - private OutputInterface $output; private int $startTime; private ?string $format = null; private ?string $message = null; private array $indicatorValues; private int $indicatorCurrent; - private int $indicatorChangeInterval; private float $indicatorUpdateTime; private bool $started = false; @@ -50,9 +48,12 @@ class ProgressIndicator * @param int $indicatorChangeInterval Change interval in milliseconds * @param array|null $indicatorValues Animated indicator characters */ - public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null) - { - $this->output = $output; + public function __construct( + private OutputInterface $output, + string $format = null, + private int $indicatorChangeInterval = 100, + array $indicatorValues = null, + ) { $format ??= $this->determineBestFormat(); $indicatorValues ??= ['-', '\\', '|', '/']; @@ -63,7 +64,6 @@ public function __construct(OutputInterface $output, string $format = null, int } $this->format = self::getFormatDefinition($format); - $this->indicatorChangeInterval = $indicatorChangeInterval; $this->indicatorValues = $indicatorValues; $this->startTime = time(); } diff --git a/Helper/Table.php b/Helper/Table.php index fd2e94d5d..87cea7f77 100644 --- a/Helper/Table.php +++ b/Helper/Table.php @@ -45,7 +45,6 @@ class Table private array $rows = []; private array $effectiveColumnWidths = []; private int $numberOfColumns; - private OutputInterface $output; private TableStyle $style; private array $columnStyles = []; private array $columnWidths = []; @@ -55,10 +54,9 @@ class Table private static array $styles; - public function __construct(OutputInterface $output) - { - $this->output = $output; - + public function __construct( + private OutputInterface $output, + ) { self::$styles ??= self::initStyles(); $this->setStyle('default'); diff --git a/Helper/TableCell.php b/Helper/TableCell.php index 394b2bc95..1c4eeea20 100644 --- a/Helper/TableCell.php +++ b/Helper/TableCell.php @@ -18,17 +18,16 @@ */ class TableCell { - private string $value; private array $options = [ 'rowspan' => 1, 'colspan' => 1, 'style' => null, ]; - public function __construct(string $value = '', array $options = []) - { - $this->value = $value; - + public function __construct( + private string $value = '', + array $options = [], + ) { // check option names if ($diff = array_diff(array_keys($options), array_keys($this->options))) { throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); diff --git a/Helper/TableRows.php b/Helper/TableRows.php index 97d07726e..fb2dc2789 100644 --- a/Helper/TableRows.php +++ b/Helper/TableRows.php @@ -16,11 +16,9 @@ */ class TableRows implements \IteratorAggregate { - private \Closure $generator; - - public function __construct(\Closure $generator) - { - $this->generator = $generator; + public function __construct( + private \Closure $generator, + ) { } public function getIterator(): \Traversable diff --git a/Input/ArrayInput.php b/Input/ArrayInput.php index 03b200b13..2697e3721 100644 --- a/Input/ArrayInput.php +++ b/Input/ArrayInput.php @@ -25,12 +25,10 @@ */ class ArrayInput extends Input { - private array $parameters; - - public function __construct(array $parameters, InputDefinition $definition = null) - { - $this->parameters = $parameters; - + public function __construct( + private array $parameters, + InputDefinition $definition = null, + ) { parent::__construct($definition); } diff --git a/Input/InputArgument.php b/Input/InputArgument.php index 642ae6600..9d6c17fa3 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -29,11 +29,8 @@ class InputArgument public const OPTIONAL = 2; public const IS_ARRAY = 4; - private string $name; private int $mode; private string|int|bool|array|null|float $default; - private array|\Closure $suggestedValues; - private string $description; /** * @param string $name The argument name @@ -44,18 +41,20 @@ class InputArgument * * @throws InvalidArgumentException When argument mode is not valid */ - public function __construct(string $name, int $mode = null, string $description = '', string|bool|int|float|array $default = null, \Closure|array $suggestedValues = []) - { + public function __construct( + private string $name, + int $mode = null, + private string $description = '', + string|bool|int|float|array $default = null, + private \Closure|array $suggestedValues = [], + ) { if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode > 7 || $mode < 1) { throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); } - $this->name = $name; $this->mode = $mode; - $this->description = $description; - $this->suggestedValues = $suggestedValues; $this->setDefault($default); } diff --git a/Input/InputOption.php b/Input/InputOption.php index f8e9b0dd6..5d305518a 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -54,8 +54,6 @@ class InputOption private string|array|null $shortcut; private int $mode; private string|int|bool|array|null|float $default; - private array|\Closure $suggestedValues; - private string $description; /** * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts @@ -65,8 +63,14 @@ class InputOption * * @throws InvalidArgumentException If option mode is invalid or incompatible */ - public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $default = null, array|\Closure $suggestedValues = []) - { + public function __construct( + string $name, + string|array $shortcut = null, + int $mode = null, + private string $description = '', + string|bool|int|float|array $default = null, + private array|\Closure $suggestedValues = [], + ) { if (str_starts_with($name, '--')) { $name = substr($name, 2); } @@ -101,8 +105,6 @@ public function __construct(string $name, string|array $shortcut = null, int $mo $this->name = $name; $this->shortcut = $shortcut; $this->mode = $mode; - $this->description = $description; - $this->suggestedValues = $suggestedValues; if ($suggestedValues && !$this->acceptValue()) { throw new LogicException('Cannot set suggested values if the option does not accept a value.'); diff --git a/Logger/ConsoleLogger.php b/Logger/ConsoleLogger.php index fddef50cd..ad6e49ce1 100644 --- a/Logger/ConsoleLogger.php +++ b/Logger/ConsoleLogger.php @@ -29,7 +29,6 @@ class ConsoleLogger extends AbstractLogger public const INFO = 'info'; public const ERROR = 'error'; - private OutputInterface $output; private array $verbosityLevelMap = [ LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, @@ -52,9 +51,11 @@ class ConsoleLogger extends AbstractLogger ]; private bool $errored = false; - public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) - { - $this->output = $output; + public function __construct( + private OutputInterface $output, + array $verbosityLevelMap = [], + array $formatLevelMap = [], + ) { $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; } diff --git a/Messenger/RunCommandMessageHandler.php b/Messenger/RunCommandMessageHandler.php index 14f9c1764..1bc499494 100644 --- a/Messenger/RunCommandMessageHandler.php +++ b/Messenger/RunCommandMessageHandler.php @@ -22,8 +22,9 @@ */ final class RunCommandMessageHandler { - public function __construct(private readonly Application $application) - { + public function __construct( + private readonly Application $application, + ) { } public function __invoke(RunCommandMessage $message): RunCommandContext diff --git a/Question/ChoiceQuestion.php b/Question/ChoiceQuestion.php index e449ff683..0ccad051c 100644 --- a/Question/ChoiceQuestion.php +++ b/Question/ChoiceQuestion.php @@ -20,7 +20,6 @@ */ class ChoiceQuestion extends Question { - private array $choices; private bool $multiselect = false; private string $prompt = ' > '; private string $errorMessage = 'Value "%s" is invalid'; @@ -30,15 +29,17 @@ class ChoiceQuestion extends Question * @param array $choices The list of available choices * @param mixed $default The default answer to return */ - public function __construct(string $question, array $choices, mixed $default = null) - { + public function __construct( + string $question, + private array $choices, + mixed $default = null, + ) { if (!$choices) { throw new \LogicException('Choice question must have at least 1 choice available.'); } parent::__construct($question, $default); - $this->choices = $choices; $this->setValidator($this->getDefaultValidator()); $this->setAutocompleterValues($choices); } diff --git a/Question/ConfirmationQuestion.php b/Question/ConfirmationQuestion.php index 40eab2429..951d68140 100644 --- a/Question/ConfirmationQuestion.php +++ b/Question/ConfirmationQuestion.php @@ -18,18 +18,18 @@ */ class ConfirmationQuestion extends Question { - private string $trueAnswerRegex; - /** * @param string $question The question to ask to the user * @param bool $default The default answer to return, true or false * @param string $trueAnswerRegex A regex to match the "yes" answer */ - public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y/i') - { + public function __construct( + string $question, + bool $default = true, + private string $trueAnswerRegex = '/^y/i', + ) { parent::__construct($question, $default); - $this->trueAnswerRegex = $trueAnswerRegex; $this->setNormalizer($this->getDefaultNormalizer()); } diff --git a/Question/Question.php b/Question/Question.php index c79683cd5..a82125c91 100644 --- a/Question/Question.php +++ b/Question/Question.php @@ -21,13 +21,11 @@ */ class Question { - private string $question; private ?int $attempts = null; private bool $hidden = false; private bool $hiddenFallback = true; private ?\Closure $autocompleterCallback = null; private ?\Closure $validator = null; - private string|int|bool|null|float $default; private ?\Closure $normalizer = null; private bool $trimmable = true; private bool $multiline = false; @@ -36,10 +34,10 @@ class Question * @param string $question The question to ask to the user * @param string|bool|int|float|null $default The default answer to return if the user enters nothing */ - public function __construct(string $question, string|bool|int|float $default = null) - { - $this->question = $question; - $this->default = $default; + public function __construct( + private string $question, + private null|string|bool|int|float $default = null, + ) { } /** diff --git a/Style/OutputStyle.php b/Style/OutputStyle.php index 05076c00f..9f62ea312 100644 --- a/Style/OutputStyle.php +++ b/Style/OutputStyle.php @@ -23,11 +23,9 @@ */ abstract class OutputStyle implements OutputInterface, StyleInterface { - private OutputInterface $output; - - public function __construct(OutputInterface $output) - { - $this->output = $output; + public function __construct( + private OutputInterface $output, + ) { } public function newLine(int $count = 1): void diff --git a/Style/SymfonyStyle.php b/Style/SymfonyStyle.php index 0da5d6981..3fd531d98 100644 --- a/Style/SymfonyStyle.php +++ b/Style/SymfonyStyle.php @@ -40,22 +40,21 @@ class SymfonyStyle extends OutputStyle { public const MAX_LINE_LENGTH = 120; - private InputInterface $input; - private OutputInterface $output; private SymfonyQuestionHelper $questionHelper; private ProgressBar $progressBar; private int $lineLength; private TrimmedBufferOutput $bufferedOutput; - public function __construct(InputInterface $input, OutputInterface $output) - { - $this->input = $input; + public function __construct( + private InputInterface $input, + private OutputInterface $output, + ) { $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter()); // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); - parent::__construct($this->output = $output); + parent::__construct($output); } /** diff --git a/Tester/ApplicationTester.php b/Tester/ApplicationTester.php index 58aee54d6..cebb6f8eb 100644 --- a/Tester/ApplicationTester.php +++ b/Tester/ApplicationTester.php @@ -28,11 +28,9 @@ class ApplicationTester { use TesterTrait; - private Application $application; - - public function __construct(Application $application) - { - $this->application = $application; + public function __construct( + private Application $application, + ) { } /** diff --git a/Tester/CommandCompletionTester.php b/Tester/CommandCompletionTester.php index a90fe52ef..76cbaf14f 100644 --- a/Tester/CommandCompletionTester.php +++ b/Tester/CommandCompletionTester.php @@ -22,11 +22,9 @@ */ class CommandCompletionTester { - private Command $command; - - public function __construct(Command $command) - { - $this->command = $command; + public function __construct( + private Command $command, + ) { } /** diff --git a/Tester/CommandTester.php b/Tester/CommandTester.php index 2ff813b7d..d39cde7f6 100644 --- a/Tester/CommandTester.php +++ b/Tester/CommandTester.php @@ -24,11 +24,9 @@ class CommandTester { use TesterTrait; - private Command $command; - - public function __construct(Command $command) - { - $this->command = $command; + public function __construct( + private Command $command, + ) { } /** From e930278484a07b8c4779d9c021b7280bfa07bfee Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Mon, 15 Jan 2024 20:49:54 +0100 Subject: [PATCH 15/59] CS: enable ordered_types.null_adjustment=always_last --- Input/InputArgument.php | 2 +- Input/InputOption.php | 2 +- Question/Question.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Input/InputArgument.php b/Input/InputArgument.php index 9d6c17fa3..521048a06 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -30,7 +30,7 @@ class InputArgument public const IS_ARRAY = 4; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; /** * @param string $name The argument name diff --git a/Input/InputOption.php b/Input/InputOption.php index 5d305518a..870f18f73 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -53,7 +53,7 @@ class InputOption private string $name; private string|array|null $shortcut; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; /** * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts diff --git a/Question/Question.php b/Question/Question.php index a82125c91..46a60c798 100644 --- a/Question/Question.php +++ b/Question/Question.php @@ -36,7 +36,7 @@ class Question */ public function __construct( private string $question, - private null|string|bool|int|float $default = null, + private string|bool|int|float|null $default = null, ) { } From 7cc16b1ffc962425545f6497c469de518bf86c49 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 29 Jan 2024 09:28:05 +0100 Subject: [PATCH 16/59] [Console] Remove needless state from QuestionHelper --- Helper/QuestionHelper.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index cb75ac914..0967156ca 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -34,11 +34,6 @@ */ class QuestionHelper extends Helper { - /** - * @var resource|null - */ - private $inputStream; - private static bool $stty = true; private static bool $stdinIsInteractive; @@ -59,16 +54,15 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu return $this->getDefaultAnswer($question); } - if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { - $this->inputStream = $stream; - } + $inputStream = $input instanceof StreamableInputInterface ? $input->getStream() : null; + $inputStream ??= STDIN; try { if (!$question->getValidator()) { - return $this->doAsk($output, $question); + return $this->doAsk($inputStream, $output, $question); } - $interviewer = fn () => $this->doAsk($output, $question); + $interviewer = fn () => $this->doAsk($inputStream, $output, $question); return $this->validateAttempts($interviewer, $output, $question); } catch (MissingInputException $exception) { @@ -98,13 +92,14 @@ public static function disableStty(): void /** * Asks the question to the user. * + * @param resource $inputStream + * * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ - private function doAsk(OutputInterface $output, Question $question): mixed + private function doAsk($inputStream, OutputInterface $output, Question $question): mixed { $this->writePrompt($output, $question); - $inputStream = $this->inputStream ?: \STDIN; $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { From f96f8d16b0a98719f3337e7f3e734d7971f7cb17 Mon Sep 17 00:00:00 2001 From: Jesper Noordsij Date: Fri, 13 Oct 2023 21:34:54 +0200 Subject: [PATCH 17/59] [Console] `InputArgument` and `InputOption` code cleanup --- Command/Command.php | 12 ++++++------ Input/InputArgument.php | 23 +++++++++++++++++------ Input/InputOption.php | 19 +++++++++++++++---- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Command/Command.php b/Command/Command.php index a9e52db94..03da6db43 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -283,7 +283,7 @@ public function run(InputInterface $input, OutputInterface $output): int } /** - * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). + * Supplies suggestions when resolving possible completion options for input (e.g. option or argument). */ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { @@ -401,8 +401,8 @@ public function getNativeDefinition(): InputDefinition /** * Adds an argument. * - * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL - * @param $default The default value (for InputArgument::OPTIONAL mode only) + * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param $default The default value (for InputArgument::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * * @return $this @@ -420,9 +420,9 @@ public function addArgument(string $name, ?int $mode = null, string $description /** * Adds an option. * - * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts - * @param $mode The option mode: One of the InputOption::VALUE_* constants - * @param $default The default value (must be null for InputOption::VALUE_NONE) + * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param $mode The option mode: One of the InputOption::VALUE_* constants + * @param $default The default value (must be null for InputOption::VALUE_NONE) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * * @return $this diff --git a/Input/InputArgument.php b/Input/InputArgument.php index c33c6a057..a049bebe5 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -25,16 +25,26 @@ */ class InputArgument { + /** + * Providing an argument is required (e.g. just 'app:foo' is not allowed). + */ public const REQUIRED = 1; + + /** + * Providing an argument is optional (e.g. 'app:foo' and 'app:foo bar' are both allowed). This is the default behavior of arguments. + */ public const OPTIONAL = 2; + + /** + * The argument accepts multiple values and turn them into an array (e.g. 'app:foo bar baz' will result in value ['bar', 'baz']). + */ public const IS_ARRAY = 4; private int $mode; - private string|int|bool|array|float|null $default; /** * @param string $name The argument name - * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY + * @param int-mask-of|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY * @param string $description A description text * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion @@ -50,7 +60,7 @@ public function __construct( ) { if (null === $mode) { $mode = self::OPTIONAL; - } elseif ($mode > 7 || $mode < 1) { + } elseif ($mode >= (self::IS_ARRAY << 1) || $mode < 1) { throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); } @@ -89,8 +99,6 @@ public function isArray(): bool /** * Sets the default value. - * - * @throws LogicException When incorrect default value is given */ public function setDefault(string|bool|int|float|array|null $default): void { @@ -117,13 +125,16 @@ public function getDefault(): string|bool|int|float|array|null return $this->default; } + /** + * Returns true if the argument has values for input completion. + */ public function hasCompletion(): bool { return [] !== $this->suggestedValues; } /** - * Adds suggestions to $suggestions for the current completion input. + * Supplies suggestions when command resolves possible completion options for input. * * @see Command::complete() */ diff --git a/Input/InputOption.php b/Input/InputOption.php index d2ebb7827..50851c44c 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -46,18 +46,18 @@ class InputOption public const VALUE_IS_ARRAY = 8; /** - * The option may have either positive or negative value (e.g. --ansi or --no-ansi). + * The option allows passing a negated variant (e.g. --ansi or --no-ansi). */ public const VALUE_NEGATABLE = 16; private string $name; - private string|array|null $shortcut; + private ?string $shortcut; private int $mode; private string|int|bool|array|float|null $default; /** * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts - * @param int|null $mode The option mode: One of the VALUE_* constants + * @param int-mask-of|null $mode The option mode: One of the VALUE_* constants * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE) * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion * @@ -175,11 +175,19 @@ public function isArray(): bool return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); } + /** + * Returns true if the option allows passing a negated variant. + * + * @return bool true if mode is self::VALUE_NEGATABLE, false otherwise + */ public function isNegatable(): bool { return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); } + /** + * Sets the default value. + */ public function setDefault(string|bool|int|float|array|null $default): void { if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { @@ -213,13 +221,16 @@ public function getDescription(): string return $this->description; } + /** + * Returns true if the option has values for input completion. + */ public function hasCompletion(): bool { return [] !== $this->suggestedValues; } /** - * Adds suggestions to $suggestions for the current completion input. + * Supplies suggestions when command resolves possible completion options for input. * * @see Command::complete() */ From 82efc31d66f28eebfc21d23736fdadf4cb258f74 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 3 Feb 2024 17:11:47 +0100 Subject: [PATCH 18/59] re-add accidentally removed property --- Input/InputArgument.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Input/InputArgument.php b/Input/InputArgument.php index a049bebe5..a5d949277 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -41,6 +41,7 @@ class InputArgument public const IS_ARRAY = 4; private int $mode; + private string|int|bool|array|float|null $default; /** * @param string $name The argument name From 63dbbae04e9d89a47183421422380330aebfd7d5 Mon Sep 17 00:00:00 2001 From: Adriaan Zonnenberg Date: Sat, 17 Feb 2024 14:49:48 +0100 Subject: [PATCH 19/59] [Console] Add descriptions to Fish completion output --- Completion/Output/FishCompletionOutput.php | 9 ++++++--- Resources/completion.fish | 6 +----- Tests/Completion/Output/FishCompletionOutputTest.php | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Completion/Output/FishCompletionOutput.php b/Completion/Output/FishCompletionOutput.php index d2c414e48..356a974ea 100644 --- a/Completion/Output/FishCompletionOutput.php +++ b/Completion/Output/FishCompletionOutput.php @@ -21,11 +21,14 @@ class FishCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void { - $values = $suggestions->getValueSuggestions(); + $values = []; + foreach ($suggestions->getValueSuggestions() as $value) { + $values[] = $value->getValue().($value->getDescription() ? "\t".$value->getDescription() : ''); + } foreach ($suggestions->getOptionSuggestions() as $option) { - $values[] = '--'.$option->getName(); + $values[] = '--'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : ''); if ($option->isNegatable()) { - $values[] = '--no-'.$option->getName(); + $values[] = '--no-'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : ''); } } $output->write(implode("\n", $values)); diff --git a/Resources/completion.fish b/Resources/completion.fish index 1c34292ae..1853dd80f 100644 --- a/Resources/completion.fish +++ b/Resources/completion.fish @@ -19,11 +19,7 @@ function _sf_{{ COMMAND_NAME }} set completecmd $completecmd "-c$c" - set sfcomplete ($completecmd) - - for i in $sfcomplete - echo $i - end + $completecmd end complete -c '{{ COMMAND_NAME }}' -a '(_sf_{{ COMMAND_NAME }})' -f diff --git a/Tests/Completion/Output/FishCompletionOutputTest.php b/Tests/Completion/Output/FishCompletionOutputTest.php index 2e615d040..93456e138 100644 --- a/Tests/Completion/Output/FishCompletionOutputTest.php +++ b/Tests/Completion/Output/FishCompletionOutputTest.php @@ -23,11 +23,11 @@ public function getCompletionOutput(): CompletionOutputInterface public function getExpectedOptionsOutput(): string { - return "--option1\n--negatable\n--no-negatable"; + return "--option1\tFirst Option\n--negatable\tCan be negative\n--no-negatable\tCan be negative"; } public function getExpectedValuesOutput(): string { - return "Green\nRed\nYellow"; + return "Green\tBeans are green\nRed\tRose are red\nYellow\tCanaries are yellow"; } } From 31c74a59d8bffdcec73adb43b398f6942f7dc26b Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 4 Mar 2024 13:46:40 +0100 Subject: [PATCH 20/59] [Console] Document argv arrays for static analysis --- Input/ArgvInput.php | 3 +++ Input/StringInput.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index 8621d62cf..6c95abc65 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -40,9 +40,11 @@ */ class ArgvInput extends Input { + /** @var list */ private array $tokens; private array $parsed; + /** @param list|null $argv */ public function __construct(?array $argv = null, ?InputDefinition $definition = null) { $argv ??= $_SERVER['argv'] ?? []; @@ -55,6 +57,7 @@ public function __construct(?array $argv = null, ?InputDefinition $definition = parent::__construct($definition); } + /** @param list $tokens */ protected function setTokens(array $tokens): void { $this->tokens = $tokens; diff --git a/Input/StringInput.php b/Input/StringInput.php index 33f0f4b39..835700143 100644 --- a/Input/StringInput.php +++ b/Input/StringInput.php @@ -40,6 +40,8 @@ public function __construct(string $input) /** * Tokenizes a string. * + * @return list + * * @throws InvalidArgumentException When unable to parse input (should never happen) */ private function tokenize(string $input): array From b66e3b8ac723816be3f9b9ba1e00cd8e19de417f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 11 Mar 2024 15:21:04 +0100 Subject: [PATCH 21/59] [Console] Add `ArgvInput::getRawTokens()` --- CHANGELOG.md | 5 +++++ Input/ArgvInput.php | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ff71d2fa..25d7f7179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.1 +--- + + * Add `ArgvInput::getRawTokens()` + 7.0 --- diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index 6c95abc65..001bef093 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -345,6 +345,16 @@ public function getParameterOption(string|array $values, string|bool|int|float|a return $default; } + /** + * Returns un-parsed and not validated tokens. + * + * @return list + */ + public function getRawTokens(): array + { + return $this->tokens; + } + /** * Returns a stringified representation of the args passed to the command. */ From 117ef1f1c1898fec311571b4be90cb4046e344f1 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sat, 2 Mar 2024 11:42:07 +0100 Subject: [PATCH 22/59] [Console] Add a way to use custom lock factory in lockableTrait --- Command/LockableTrait.php | 16 ++++++++----- Tests/Command/LockableTraitTest.php | 16 +++++++++++++ Tests/Fixtures/FooLock3Command.php | 35 +++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 Tests/Fixtures/FooLock3Command.php diff --git a/Command/LockableTrait.php b/Command/LockableTrait.php index cd7548f02..f0001cc52 100644 --- a/Command/LockableTrait.php +++ b/Command/LockableTrait.php @@ -26,6 +26,8 @@ trait LockableTrait { private ?LockInterface $lock = null; + private ?LockFactory $lockFactory = null; + /** * Locks a command. */ @@ -39,13 +41,17 @@ private function lock(?string $name = null, bool $blocking = false): bool throw new LogicException('A lock is already in place.'); } - if (SemaphoreStore::isSupported()) { - $store = new SemaphoreStore(); - } else { - $store = new FlockStore(); + if (null === $this->lockFactory) { + if (SemaphoreStore::isSupported()) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(); + } + + $this->lockFactory = (new LockFactory($store)); } - $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName()); + $this->lock = $this->lockFactory->createLock($name ?: $this->getName()); if (!$this->lock->acquire($blocking)) { $this->lock = null; diff --git a/Tests/Command/LockableTraitTest.php b/Tests/Command/LockableTraitTest.php index 77b54f9ee..0268d9681 100644 --- a/Tests/Command/LockableTraitTest.php +++ b/Tests/Command/LockableTraitTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Lock\LockFactory; +use Symfony\Component\Lock\SharedLockInterface; use Symfony\Component\Lock\Store\FlockStore; use Symfony\Component\Lock\Store\SemaphoreStore; @@ -26,6 +27,7 @@ public static function setUpBeforeClass(): void self::$fixturesPath = __DIR__.'/../Fixtures/'; require_once self::$fixturesPath.'/FooLockCommand.php'; require_once self::$fixturesPath.'/FooLock2Command.php'; + require_once self::$fixturesPath.'/FooLock3Command.php'; } public function testLockIsReleased() @@ -64,4 +66,18 @@ public function testMultipleLockCallsThrowLogicException() $tester = new CommandTester($command); $this->assertSame(1, $tester->execute([])); } + + public function testCustomLockFactoryIsUsed() + { + $lockFactory = $this->createMock(LockFactory::class); + $command = new \FooLock3Command($lockFactory); + + $tester = new CommandTester($command); + + $lock = $this->createMock(SharedLockInterface::class); + $lock->method('acquire')->willReturn(false); + + $lockFactory->expects(static::once())->method('createLock')->willReturn($lock); + $this->assertSame(1, $tester->execute([])); + } } diff --git a/Tests/Fixtures/FooLock3Command.php b/Tests/Fixtures/FooLock3Command.php new file mode 100644 index 000000000..78492de69 --- /dev/null +++ b/Tests/Fixtures/FooLock3Command.php @@ -0,0 +1,35 @@ +lockFactory = $lockFactory; + } + + protected function configure(): void + { + $this->setName('foo:lock3'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + if (!$this->lock()) { + return 1; + } + + $this->release(); + + return 2; + } +} From 07520ebce9e125cb845805626bced597d585faa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 20 Mar 2024 11:51:16 +0100 Subject: [PATCH 23/59] [Console] Allow to returns all tokens after the command name --- Input/ArgvInput.php | 23 +++++++++++++++++++++-- Tests/Input/ArgvInputTest.php | 27 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index 001bef093..95703ba5f 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -348,11 +348,30 @@ public function getParameterOption(string|array $values, string|bool|int|float|a /** * Returns un-parsed and not validated tokens. * + * @param bool $strip Whether to return the raw parameters (false) or the values after the command name (true) + * * @return list */ - public function getRawTokens(): array + public function getRawTokens(bool $strip = false): array { - return $this->tokens; + if (!$strip) { + return $this->tokens; + } + + $parameters = []; + $keep = false; + foreach ($this->tokens as $value) { + if (!$keep && $value === $this->getFirstArgument()) { + $keep = true; + + continue; + } + if ($keep) { + $parameters[] = $value; + } + } + + return $parameters; } /** diff --git a/Tests/Input/ArgvInputTest.php b/Tests/Input/ArgvInputTest.php index a47d557b7..80ea06d67 100644 --- a/Tests/Input/ArgvInputTest.php +++ b/Tests/Input/ArgvInputTest.php @@ -562,4 +562,31 @@ public function testParseOptionWithValueOptionalGivenEmptyAndOptionalArgument() $this->assertEquals(['foo' => '0'], $input->getOptions(), '->parse() parses optional options with empty value as null'); $this->assertEquals(['name' => 'bar'], $input->getArguments(), '->parse() parses optional arguments'); } + + public function testGetRawTokensFalse() + { + $input = new ArgvInput(['cli.php', '--foo', 'bar']); + $this->assertSame(['--foo', 'bar'], $input->getRawTokens()); + } + + /** + * @dataProvider provideGetRawTokensTrueTests + */ + public function testGetRawTokensTrue(array $argv, array $expected) + { + $input = new ArgvInput($argv); + $this->assertSame($expected, $input->getRawTokens(true)); + } + + public static function provideGetRawTokensTrueTests(): iterable + { + yield [['app/console', 'foo:bar'], []]; + yield [['app/console', 'foo:bar', '--env=prod'], ['--env=prod']]; + yield [['app/console', 'foo:bar', '--env', 'prod'], ['--env', 'prod']]; + yield [['app/console', '--no-ansi', 'foo:bar', '--env', 'prod'], ['--env', 'prod']]; + yield [['app/console', '--no-ansi', 'foo:bar', '--env', 'prod'], ['--env', 'prod']]; + yield [['app/console', '--no-ansi', 'foo:bar', 'argument'], ['argument']]; + yield [['app/console', '--no-ansi', 'foo:bar', 'foo:bar'], ['foo:bar']]; + yield [['app/console', '--no-ansi', 'foo:bar', '--', 'argument'], ['--', 'argument']]; + } } From e5b4db4db27704fc0e153eacbe001feddeab0480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sun, 31 Mar 2024 15:15:18 +0200 Subject: [PATCH 24/59] Remove unnecessary empty usages --- Application.php | 6 +++--- Descriptor/XmlDescriptor.php | 2 +- Helper/Table.php | 2 +- Input/InputOption.php | 2 +- Output/ConsoleSectionOutput.php | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Application.php b/Application.php index 9c301471c..3f7ef0419 100644 --- a/Application.php +++ b/Application.php @@ -620,7 +620,7 @@ public function findNamespace(string $namespace): string $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $namespace))).'[^:]*'; $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); - if (empty($namespaces)) { + if (!$namespaces) { $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { @@ -674,12 +674,12 @@ public function find(string $name): Command $expr = implode('[^:]*:', array_map('preg_quote', explode(':', $name))).'[^:]*'; $commands = preg_grep('{^'.$expr.'}', $allCommands); - if (empty($commands)) { + if (!$commands) { $commands = preg_grep('{^'.$expr.'}i', $allCommands); } // if no commands matched or we just matched namespaces - if (empty($commands) || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) { + if (!$commands || \count(preg_grep('{^'.$expr.'$}i', $commands)) < 1) { if (false !== $pos = strrpos($name, ':')) { // check if a namespace exists and contains commands $this->findNamespace(substr($name, 0, $pos)); diff --git a/Descriptor/XmlDescriptor.php b/Descriptor/XmlDescriptor.php index 866c71856..8e44c88c4 100644 --- a/Descriptor/XmlDescriptor.php +++ b/Descriptor/XmlDescriptor.php @@ -208,7 +208,7 @@ private function getInputOptionDocument(InputOption $option): \DOMDocument $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : [])); $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); - if (!empty($defaults)) { + if ($defaults) { foreach ($defaults as $default) { $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); $defaultXML->appendChild($dom->createTextNode($default)); diff --git a/Helper/Table.php b/Helper/Table.php index c1b7dba59..afdb67c49 100644 --- a/Helper/Table.php +++ b/Helper/Table.php @@ -726,7 +726,7 @@ private function fillNextRows(array $rows, int $line): array } else { $row = $this->copyRow($rows, $unmergedRowKey - 1); foreach ($unmergedRow as $column => $cell) { - if (!empty($cell)) { + if ($cell) { $row[$column] = $cell; } } diff --git a/Input/InputOption.php b/Input/InputOption.php index 50851c44c..617c348d5 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -75,7 +75,7 @@ public function __construct( $name = substr($name, 2); } - if (empty($name)) { + if (!$name) { throw new InvalidArgumentException('An option name cannot be empty.'); } diff --git a/Output/ConsoleSectionOutput.php b/Output/ConsoleSectionOutput.php index ded97c70e..09aa7fe99 100644 --- a/Output/ConsoleSectionOutput.php +++ b/Output/ConsoleSectionOutput.php @@ -63,7 +63,7 @@ public function setMaxHeight(int $maxHeight): void */ public function clear(?int $lines = null): void { - if (empty($this->content) || !$this->isDecorated()) { + if (!$this->content || !$this->isDecorated()) { return; } From 1b84910b638ce3265e132d7b42405b2db64f6f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sat, 6 Apr 2024 19:21:51 +0200 Subject: [PATCH 25/59] [Console] Handle SIGQUIT signal As both PHP-FPM and NGINX use SIGQUIT for graceful shutdown, I believe it's necessary PHP applications should also support it. It's especially important in cases where you run PHP application in container running php/nginx image, since they override shutdown signal that docker uses to SIGQUIT, see https://github.com/nginxinc/docker-nginx/commit/3fb70ddd7094c1fdd50cc83d432643dc10ab6243 --- Application.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Application.php b/Application.php index 3f7ef0419..87eb7a6c2 100644 --- a/Application.php +++ b/Application.php @@ -97,7 +97,7 @@ public function __construct( $this->defaultCommand = 'list'; if (\defined('SIGINT') && SignalRegistry::isSupported()) { $this->signalRegistry = new SignalRegistry(); - $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; + $this->signalsToDispatchEvent = [\SIGINT, \SIGQUIT, \SIGTERM, \SIGUSR1, \SIGUSR2]; } } @@ -984,7 +984,7 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI if (Terminal::hasSttyAvailable()) { $sttyMode = shell_exec('stty -g'); - foreach ([\SIGINT, \SIGTERM] as $signal) { + foreach ([\SIGINT, \SIGQUIT, \SIGTERM] as $signal) { $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); } } From 965f054b640b28a4cfaa77cc69b53506393e3a4a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 2 May 2024 13:32:55 +0200 Subject: [PATCH 26/59] Cleanup past sponsors --- README.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ded2bc116..92f70e714 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,7 @@ interfaces. Sponsor ------- -The Console component for Symfony 7.0 is [backed][1] by [Les-Tilleuls.coop][2]. - -Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and -fix your projects. They provide a wide range of professional services including development, -consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps. -They are a worker cooperative! - -Help Symfony by [sponsoring][3] its development! +Help Symfony by [sponsoring][1] its development! Resources --------- @@ -31,6 +24,4 @@ Credits `Resources/bin/hiddeninput.exe` is a third party binary provided within this component. Find sources and license at https://github.com/Seldaek/hidden-input. -[1]: https://symfony.com/backers -[2]: https://les-tilleuls.coop -[3]: https://symfony.com/sponsor +[1]: https://symfony.com/sponsor From a1b3df8a0a0f883244a843ee806dd9cabc5441d7 Mon Sep 17 00:00:00 2001 From: Kev Date: Fri, 12 Apr 2024 10:46:21 +0200 Subject: [PATCH 27/59] [Console] Better error handling when misuse of `ArgvInput` with arrays --- Input/ArgvInput.php | 6 ++++++ Tests/Input/ArgvInputTest.php | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index 95703ba5f..2ebbdf086 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -49,6 +49,12 @@ public function __construct(?array $argv = null, ?InputDefinition $definition = { $argv ??= $_SERVER['argv'] ?? []; + foreach ($argv as $arg) { + if (!\is_scalar($arg) && !$arg instanceof \Stringable) { + throw new RuntimeException(sprintf('Argument values expected to be all scalars, got "%s".', get_debug_type($arg))); + } + } + // strip the application name array_shift($argv); diff --git a/Tests/Input/ArgvInputTest.php b/Tests/Input/ArgvInputTest.php index 80ea06d67..31b4b03dd 100644 --- a/Tests/Input/ArgvInputTest.php +++ b/Tests/Input/ArgvInputTest.php @@ -324,6 +324,11 @@ public static function provideInvalidInput(): array new InputDefinition([new InputArgument('name', InputArgument::REQUIRED)]), 'Too many arguments, expected arguments "name".', ], + [ + ['cli.php', ['array']], + new InputDefinition(), + 'Argument values expected to be all scalars, got "array".', + ], ]; } From d4f689163104d1f2fbbdd78923b36e6ca8c501de Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 20 Jun 2024 17:52:34 +0200 Subject: [PATCH 28/59] Prefix all sprintf() calls --- Application.php | 36 +++++++++---------- CI/GithubActionReporter.php | 4 +-- Color.php | 8 ++--- Command/Command.php | 10 +++--- Command/CompleteCommand.php | 4 +-- Command/DumpCompletionCommand.php | 4 +-- CommandLoader/ContainerCommandLoader.php | 2 +- CommandLoader/FactoryCommandLoader.php | 2 +- Cursor.php | 14 ++++---- DataCollector/CommandDataCollector.php | 6 ++-- DependencyInjection/AddConsoleCommandPass.php | 8 ++--- Descriptor/ApplicationDescription.php | 2 +- Descriptor/Descriptor.php | 2 +- Descriptor/MarkdownDescriptor.php | 4 +-- Descriptor/ReStructuredTextDescriptor.php | 4 +-- Descriptor/TextDescriptor.php | 20 +++++------ Formatter/OutputFormatter.php | 2 +- Helper/DebugFormatterHelper.php | 16 ++++----- Helper/DescriptorHelper.php | 2 +- Helper/FormatterHelper.php | 6 ++-- Helper/Helper.php | 8 ++--- Helper/HelperSet.php | 2 +- Helper/OutputWrapper.php | 4 +-- Helper/ProcessHelper.php | 6 ++-- Helper/ProgressBar.php | 2 +- Helper/QuestionHelper.php | 2 +- Helper/SymfonyQuestionHelper.php | 12 +++---- Helper/Table.php | 32 ++++++++--------- Helper/TableCell.php | 2 +- Helper/TableCellStyle.php | 4 +-- Input/ArgvInput.php | 22 ++++++------ Input/ArrayInput.php | 8 ++--- Input/Input.php | 10 +++--- Input/InputArgument.php | 4 +-- Input/InputDefinition.php | 30 ++++++++-------- Input/InputOption.php | 4 +-- Input/StringInput.php | 2 +- Logger/ConsoleLogger.php | 4 +-- Messenger/RunCommandMessageHandler.php | 2 +- Output/AnsiColorMode.php | 4 +-- Output/ConsoleSectionOutput.php | 2 +- Output/TrimmedBufferOutput.php | 2 +- Question/ChoiceQuestion.php | 6 ++-- Style/SymfonyStyle.php | 16 ++++----- Tester/Constraint/CommandIsSuccessful.php | 2 +- Tests/ApplicationTest.php | 8 ++--- Tests/Command/CommandTest.php | 2 +- .../Descriptor/AbstractDescriptorTestCase.php | 2 +- Tests/Helper/ProgressIndicatorTest.php | 2 +- Tests/Input/InputDefinitionTest.php | 2 +- Tests/Output/ConsoleSectionOutputTest.php | 6 ++-- Tests/Question/ConfirmationQuestionTest.php | 2 +- 52 files changed, 186 insertions(+), 186 deletions(-) diff --git a/Application.php b/Application.php index 87eb7a6c2..aa4af5c58 100644 --- a/Application.php +++ b/Application.php @@ -262,9 +262,9 @@ public function doRun(InputInterface $input, OutputInterface $output): int $style = new SymfonyStyle($input, $output); $output->writeln(''); - $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true); + $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', true); $output->writeln($formattedBlock); - if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) { + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), false)) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); @@ -475,7 +475,7 @@ public function getLongVersion(): string { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { - return sprintf('%s %s', $this->getName(), $this->getVersion()); + return \sprintf('%s %s', $this->getName(), $this->getVersion()); } return $this->getName(); @@ -530,7 +530,7 @@ public function add(Command $command): ?Command } if (!$command->getName()) { - throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); } $this->commands[$command->getName()] = $command; @@ -552,12 +552,12 @@ public function get(string $name): Command $this->init(); if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } // When the command has a different name than the one used at the command loader level if (!isset($this->commands[$name])) { - throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); } $command = $this->commands[$name]; @@ -621,7 +621,7 @@ public function findNamespace(string $namespace): string $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); if (!$namespaces) { - $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == \count($alternatives)) { @@ -638,7 +638,7 @@ public function findNamespace(string $namespace): string $exact = \in_array($namespace, $namespaces, true); if (\count($namespaces) > 1 && !$exact) { - throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); } return $exact ? $namespace : reset($namespaces); @@ -685,7 +685,7 @@ public function find(string $name): Command $this->findNamespace(substr($name, 0, $pos)); } - $message = sprintf('Command "%s" is not defined.', $name); + $message = \sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands @@ -740,14 +740,14 @@ public function find(string $name): Command if (\count($commands) > 1) { $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs)); - throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); } } $command = $this->get(reset($commands)); if ($command->isHidden()) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } return $command; @@ -822,7 +822,7 @@ public function renderThrowable(\Throwable $e, OutputInterface $output): void $this->doRenderThrowable($e, $output); if (null !== $this->runningCommand) { - $output->writeln(sprintf('%s', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } @@ -833,7 +833,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $message = trim($e->getMessage()); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $class = get_debug_type($e); - $title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); $len = Helper::width($title); } else { $len = 0; @@ -857,14 +857,14 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $messages = []; if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } - $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); + $messages[] = $emptyLine = \sprintf('%s', str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); + $messages[] = \sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { - $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; @@ -891,7 +891,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $file = $trace[$i]['file'] ?? 'n/a'; $line = $trace[$i]['line'] ?? 'n/a'; - $output->writeln(sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); } $output->writeln('', OutputInterface::VERBOSITY_QUIET); diff --git a/CI/GithubActionReporter.php b/CI/GithubActionReporter.php index 2cae6fd8b..28112c2a2 100644 --- a/CI/GithubActionReporter.php +++ b/CI/GithubActionReporter.php @@ -89,11 +89,11 @@ private function log(string $type, string $message, ?string $file = null, ?int $ if (!$file) { // No file provided, output the message solely: - $this->output->writeln(sprintf('::%s::%s', $type, $message)); + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); return; } - $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); } } diff --git a/Color.php b/Color.php index 60ed046a6..b1914c19a 100644 --- a/Color.php +++ b/Color.php @@ -60,7 +60,7 @@ public function __construct(string $foreground = '', string $background = '', ar foreach ($options as $option) { if (!isset(self::AVAILABLE_OPTIONS[$option])) { - throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); } $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; @@ -88,7 +88,7 @@ public function set(): string return ''; } - return sprintf("\033[%sm", implode(';', $setCodes)); + return \sprintf("\033[%sm", implode(';', $setCodes)); } public function unset(): string @@ -107,7 +107,7 @@ public function unset(): string return ''; } - return sprintf("\033[%sm", implode(';', $unsetCodes)); + return \sprintf("\033[%sm", implode(';', $unsetCodes)); } private function parseColor(string $color, bool $background = false): string @@ -128,6 +128,6 @@ private function parseColor(string $color, bool $background = false): string return ($background ? '10' : '9').self::BRIGHT_COLORS[$color]; } - throw new InvalidArgumentException(sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); } } diff --git a/Command/Command.php b/Command/Command.php index 03da6db43..244a419f2 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -395,7 +395,7 @@ public function getDefinition(): InputDefinition */ public function getNativeDefinition(): InputDefinition { - return $this->definition ?? throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); + return $this->definition ?? throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); } /** @@ -603,7 +603,7 @@ public function getSynopsis(bool $short = false): string $key = $short ? 'short' : 'long'; if (!isset($this->synopsis[$key])) { - $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + $this->synopsis[$key] = trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); } return $this->synopsis[$key]; @@ -617,7 +617,7 @@ public function getSynopsis(bool $short = false): string public function addUsage(string $usage): static { if (!str_starts_with($usage, $this->name)) { - $usage = sprintf('%s %s', $this->name, $usage); + $usage = \sprintf('%s %s', $this->name, $usage); } $this->usages[] = $usage; @@ -642,7 +642,7 @@ public function getUsages(): array public function getHelper(string $name): HelperInterface { if (null === $this->helperSet) { - throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); + throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); } return $this->helperSet->get($name); @@ -658,7 +658,7 @@ public function getHelper(string $name): HelperInterface private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { - throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); } } } diff --git a/Command/CompleteCommand.php b/Command/CompleteCommand.php index 38aa737f0..df0cddabb 100644 --- a/Command/CompleteCommand.php +++ b/Command/CompleteCommand.php @@ -74,7 +74,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1 $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version'); if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) { - $message = sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); + $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); $this->log($message); $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); @@ -88,7 +88,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (!$completionOutput = $this->completionOutputs[$shell] ?? false) { - throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); + throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); } $completionInput = $this->createCompletionInput($input); diff --git a/Command/DumpCompletionCommand.php b/Command/DumpCompletionCommand.php index be6f54592..daf3553ab 100644 --- a/Command/DumpCompletionCommand.php +++ b/Command/DumpCompletionCommand.php @@ -98,9 +98,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output = $output->getErrorOutput(); } if ($shell) { - $output->writeln(sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); + $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); } else { - $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); + $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } return 2; diff --git a/CommandLoader/ContainerCommandLoader.php b/CommandLoader/ContainerCommandLoader.php index 84e25be76..eb4945135 100644 --- a/CommandLoader/ContainerCommandLoader.php +++ b/CommandLoader/ContainerCommandLoader.php @@ -34,7 +34,7 @@ public function __construct( public function get(string $name): Command { if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->container->get($this->commandMap[$name]); diff --git a/CommandLoader/FactoryCommandLoader.php b/CommandLoader/FactoryCommandLoader.php index ae16bf6f1..2d13139c2 100644 --- a/CommandLoader/FactoryCommandLoader.php +++ b/CommandLoader/FactoryCommandLoader.php @@ -37,7 +37,7 @@ public function has(string $name): bool public function get(string $name): Command { if (!isset($this->factories[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } $factory = $this->factories[$name]; diff --git a/Cursor.php b/Cursor.php index 965f996e0..e2618cf1d 100644 --- a/Cursor.php +++ b/Cursor.php @@ -36,7 +36,7 @@ public function __construct( */ public function moveUp(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dA", $lines)); + $this->output->write(\sprintf("\x1b[%dA", $lines)); return $this; } @@ -46,7 +46,7 @@ public function moveUp(int $lines = 1): static */ public function moveDown(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dB", $lines)); + $this->output->write(\sprintf("\x1b[%dB", $lines)); return $this; } @@ -56,7 +56,7 @@ public function moveDown(int $lines = 1): static */ public function moveRight(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dC", $columns)); + $this->output->write(\sprintf("\x1b[%dC", $columns)); return $this; } @@ -66,7 +66,7 @@ public function moveRight(int $columns = 1): static */ public function moveLeft(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dD", $columns)); + $this->output->write(\sprintf("\x1b[%dD", $columns)); return $this; } @@ -76,7 +76,7 @@ public function moveLeft(int $columns = 1): static */ public function moveToColumn(int $column): static { - $this->output->write(sprintf("\x1b[%dG", $column)); + $this->output->write(\sprintf("\x1b[%dG", $column)); return $this; } @@ -86,7 +86,7 @@ public function moveToColumn(int $column): static */ public function moveToPosition(int $column, int $row): static { - $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column)); + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); return $this; } @@ -195,7 +195,7 @@ public function getCurrentPosition(): array $code = trim(fread($this->input, 1024)); - shell_exec(sprintf('stty %s', $sttyMode)); + shell_exec(\sprintf('stty %s', $sttyMode)); sscanf($code, "\033[%d;%dR", $row, $col); diff --git a/DataCollector/CommandDataCollector.php b/DataCollector/CommandDataCollector.php index 45138c7dc..3cbe72b59 100644 --- a/DataCollector/CommandDataCollector.php +++ b/DataCollector/CommandDataCollector.php @@ -118,7 +118,7 @@ public function getCommand(): array public function getInterruptedBySignal(): ?string { if (isset($this->data['interrupted_by_signal'])) { - return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); } return null; @@ -204,7 +204,7 @@ public function getInteractiveInputs(): array public function getSignalable(): array { return array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), $this->data['signalable'] ); } @@ -212,7 +212,7 @@ public function getSignalable(): array public function getHandledSignals(): array { $keys = array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), array_keys($this->data['handled_signals']) ); diff --git a/DependencyInjection/AddConsoleCommandPass.php b/DependencyInjection/AddConsoleCommandPass.php index f712c614a..642247e3f 100644 --- a/DependencyInjection/AddConsoleCommandPass.php +++ b/DependencyInjection/AddConsoleCommandPass.php @@ -45,10 +45,10 @@ public function process(ContainerBuilder $container): void $aliases = $tags[0]['command']; } else { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { - throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); } @@ -102,10 +102,10 @@ public function process(ContainerBuilder $container): void if (!$description) { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { - throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $description = str_replace('%', '%%', $class::getDefaultDescription() ?? ''); } diff --git a/Descriptor/ApplicationDescription.php b/Descriptor/ApplicationDescription.php index 5149fde4c..802d68560 100644 --- a/Descriptor/ApplicationDescription.php +++ b/Descriptor/ApplicationDescription.php @@ -70,7 +70,7 @@ public function getCommands(): array public function getCommand(string $name): Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->commands[$name] ?? $this->aliases[$name]; diff --git a/Descriptor/Descriptor.php b/Descriptor/Descriptor.php index 7b2509c60..2143a17c3 100644 --- a/Descriptor/Descriptor.php +++ b/Descriptor/Descriptor.php @@ -38,7 +38,7 @@ public function describe(OutputInterface $output, object $object, array $options $object instanceof InputDefinition => $this->describeInputDefinition($object, $options), $object instanceof Command => $this->describeCommand($object, $options), $object instanceof Application => $this->describeApplication($object, $options), - default => throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))), + default => throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))), }; } diff --git a/Descriptor/MarkdownDescriptor.php b/Descriptor/MarkdownDescriptor.php index b3f16ee90..8b7075943 100644 --- a/Descriptor/MarkdownDescriptor.php +++ b/Descriptor/MarkdownDescriptor.php @@ -149,7 +149,7 @@ protected function describeApplication(Application $application, array $options } $this->write("\n\n"); - $this->write(implode("\n", array_map(fn ($commandName) => sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); + $this->write(implode("\n", array_map(fn ($commandName) => \sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); } foreach ($description->getCommands() as $command) { @@ -162,7 +162,7 @@ private function getApplicationTitle(Application $application): string { if ('UNKNOWN' !== $application->getName()) { if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); diff --git a/Descriptor/ReStructuredTextDescriptor.php b/Descriptor/ReStructuredTextDescriptor.php index f12fecb67..462b9bb0b 100644 --- a/Descriptor/ReStructuredTextDescriptor.php +++ b/Descriptor/ReStructuredTextDescriptor.php @@ -167,7 +167,7 @@ private function getApplicationTitle(Application $application): string return 'Console Tool'; } if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); @@ -209,7 +209,7 @@ private function createTableOfContents(ApplicationDescription $description, Appl $commands = $this->removeAliasesAndHiddenCommands($commands); $this->write("\n\n"); - $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); + $this->write(implode("\n", array_map(static fn ($commandName) => \sprintf('- `%s`_', $commandName), array_keys($commands)))); } } diff --git a/Descriptor/TextDescriptor.php b/Descriptor/TextDescriptor.php index d04d10238..51c411f46 100644 --- a/Descriptor/TextDescriptor.php +++ b/Descriptor/TextDescriptor.php @@ -31,7 +31,7 @@ class TextDescriptor extends Descriptor protected function describeInputArgument(InputArgument $argument, array $options = []): void { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } @@ -39,7 +39,7 @@ protected function describeInputArgument(InputArgument $argument, array $options $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); - $this->writeText(sprintf(' %s %s%s%s', + $this->writeText(\sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -51,7 +51,7 @@ protected function describeInputArgument(InputArgument $argument, array $options protected function describeInputOption(InputOption $option, array $options = []): void { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); } else { $default = ''; } @@ -66,14 +66,14 @@ protected function describeInputOption(InputOption $option, array $options = []) } $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); - $synopsis = sprintf('%s%s', - $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', - sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) + $synopsis = \sprintf('%s%s', + $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', + \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) ); $spacingWidth = $totalWidth - Helper::width($synopsis); - $this->writeText(sprintf(' %s %s%s%s%s', + $this->writeText(\sprintf(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -166,7 +166,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth($description->getCommands()); foreach ($description->getCommands() as $command) { - $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); $this->writeText("\n"); } } else { @@ -196,7 +196,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); if ($describedNamespace) { - $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $options); } @@ -218,7 +218,7 @@ protected function describeApplication(Application $application, array $options $spacingWidth = $width - Helper::width($name); $command = $commands[$name]; $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; - $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); + $this->writeText(\sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); } } diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php index 8e81e5900..1f3d04a2e 100644 --- a/Formatter/OutputFormatter.php +++ b/Formatter/OutputFormatter.php @@ -106,7 +106,7 @@ public function hasStyle(string $name): bool public function getStyle(string $name): OutputFormatterStyleInterface { if (!$this->hasStyle($name)) { - throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name)); + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); } return $this->styles[strtolower($name)]; diff --git a/Helper/DebugFormatterHelper.php b/Helper/DebugFormatterHelper.php index 9ea7fb914..dfdb8a82c 100644 --- a/Helper/DebugFormatterHelper.php +++ b/Helper/DebugFormatterHelper.php @@ -31,7 +31,7 @@ public function start(string $id, string $message, string $prefix = 'RUN'): stri { $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; - return sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); } /** @@ -47,22 +47,22 @@ public function progress(string $id, string $buffer, bool $error = false, string unset($this->started[$id]['out']); } if (!isset($this->started[$id]['err'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); } else { if (isset($this->started[$id]['err'])) { $message .= "\n"; unset($this->started[$id]['err']); } if (!isset($this->started[$id]['out'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $prefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); } return $message; @@ -76,10 +76,10 @@ public function stop(string $id, string $message, bool $successful, string $pref $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; if ($successful) { - return sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } - $message = sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); unset($this->started[$id]['out'], $this->started[$id]['err']); @@ -88,7 +88,7 @@ public function stop(string $id, string $message, bool $successful, string $pref private function getBorder(string $id): string { - return sprintf(' ', self::COLORS[$this->started[$id]['border']]); + return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); } public function getName(): string diff --git a/Helper/DescriptorHelper.php b/Helper/DescriptorHelper.php index 300c7b102..9422271fb 100644 --- a/Helper/DescriptorHelper.php +++ b/Helper/DescriptorHelper.php @@ -60,7 +60,7 @@ public function describe(OutputInterface $output, ?object $object, array $option ], $options); if (!isset($this->descriptors[$options['format']])) { - throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format'])); + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); } $descriptor = $this->descriptors[$options['format']]; diff --git a/Helper/FormatterHelper.php b/Helper/FormatterHelper.php index 279e4c799..3646b3d6f 100644 --- a/Helper/FormatterHelper.php +++ b/Helper/FormatterHelper.php @@ -25,7 +25,7 @@ class FormatterHelper extends Helper */ public function formatSection(string $section, string $message, string $style = 'info'): string { - return sprintf('<%s>[%s] %s', $style, $section, $style, $message); + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); } /** @@ -41,7 +41,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = $lines = []; foreach ($messages as $message) { $message = OutputFormatter::escape($message); - $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); $len = max(self::width($message) + ($large ? 4 : 2), $len); } @@ -54,7 +54,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = } for ($i = 0; isset($messages[$i]); ++$i) { - $messages[$i] = sprintf('<%s>%s', $style, $messages[$i], $style); + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); } return implode("\n", $messages); diff --git a/Helper/Helper.php b/Helper/Helper.php index de090063a..3981bbf3a 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -128,18 +128,18 @@ public static function formatTime(int|float $secs, int $precision = 1): string public static function formatMemory(int $memory): string { if ($memory >= 1024 * 1024 * 1024) { - return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); } if ($memory >= 1024 * 1024) { - return sprintf('%.1f MiB', $memory / 1024 / 1024); + return \sprintf('%.1f MiB', $memory / 1024 / 1024); } if ($memory >= 1024) { - return sprintf('%d KiB', $memory / 1024); + return \sprintf('%d KiB', $memory / 1024); } - return sprintf('%d B', $memory); + return \sprintf('%d B', $memory); } public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string): string diff --git a/Helper/HelperSet.php b/Helper/HelperSet.php index 30df9f958..ffe756c9d 100644 --- a/Helper/HelperSet.php +++ b/Helper/HelperSet.php @@ -61,7 +61,7 @@ public function has(string $name): bool public function get(string $name): HelperInterface { if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); } return $this->helpers[$name]; diff --git a/Helper/OutputWrapper.php b/Helper/OutputWrapper.php index 0ea2b7056..a615ed2f9 100644 --- a/Helper/OutputWrapper.php +++ b/Helper/OutputWrapper.php @@ -59,7 +59,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string return $text; } - $tagPattern = sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); + $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); $limitPattern = "{1,$width}"; $patternBlocks = [$tagPattern]; if (!$this->allowCutUrls) { @@ -68,7 +68,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string $patternBlocks[] = '.'; $blocks = implode('|', $patternBlocks); $rowPattern = "(?:$blocks)$limitPattern"; - $pattern = sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); + $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break); return str_replace(' '.$break, $break, $output); diff --git a/Helper/ProcessHelper.php b/Helper/ProcessHelper.php index 3ef6f71f7..ae55a83c2 100644 --- a/Helper/ProcessHelper.php +++ b/Helper/ProcessHelper.php @@ -55,7 +55,7 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process = $cmd[0]; unset($cmd[0]); } else { - throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); } if ($verbosity <= $output->getVerbosity()) { @@ -69,12 +69,12 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process->run($callback, $cmd); if ($verbosity <= $output->getVerbosity()) { - $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode()); + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); } if (!$process->isSuccessful() && null !== $error) { - $output->writeln(sprintf('%s', $this->escapeString($error))); + $output->writeln(\sprintf('%s', $this->escapeString($error))); } return $process; diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index 7c22b7d55..5f1a32bc9 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -621,7 +621,7 @@ private function buildLine(): string } if (isset($matches[2])) { - $text = sprintf('%'.$matches[2], $text); + $text = \sprintf('%'.$matches[2], $text); } return $text; diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index 54825c6cd..69afc2a67 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -211,7 +211,7 @@ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string foreach ($choices as $key => $value) { $padding = str_repeat(' ', $maxWidth - self::width($key)); - $messages[] = sprintf(" [<$tag>%s$padding] %s", $key, $value); + $messages[] = \sprintf(" [<$tag>%s$padding] %s", $key, $value); } return $messages; diff --git a/Helper/SymfonyQuestionHelper.php b/Helper/SymfonyQuestionHelper.php index 48d947b75..b452bf047 100644 --- a/Helper/SymfonyQuestionHelper.php +++ b/Helper/SymfonyQuestionHelper.php @@ -31,17 +31,17 @@ protected function writePrompt(OutputInterface $output, Question $question): voi $default = $question->getDefault(); if ($question->isMultiline()) { - $text .= sprintf(' (press %s to continue)', $this->getEofShortcut()); + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); } switch (true) { case null === $default: - $text = sprintf(' %s:', $text); + $text = \sprintf(' %s:', $text); break; case $question instanceof ConfirmationQuestion: - $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); break; @@ -53,18 +53,18 @@ protected function writePrompt(OutputInterface $output, Question $question): voi $default[$key] = $choices[trim($value)]; } - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); diff --git a/Helper/Table.php b/Helper/Table.php index 09709a28e..9ff73d2cc 100644 --- a/Helper/Table.php +++ b/Helper/Table.php @@ -79,7 +79,7 @@ public static function getStyleDefinition(string $name): TableStyle { self::$styles ??= self::initStyles(); - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } /** @@ -164,7 +164,7 @@ public function setColumnWidths(array $widths): static public function setColumnMaxWidth(int $columnIndex, int $width): static { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { - throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; @@ -233,7 +233,7 @@ public function addRow(TableSeparator|array $row): static public function appendRow(TableSeparator|array $row): static { if (!$this->output instanceof ConsoleSectionOutput) { - throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { @@ -364,14 +364,14 @@ public function render(): void foreach ($parts as $idx => $part) { if ($headers && !$containsColspan) { if (0 === $idx) { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s%s: %s', str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), $headers[$i] ?? '', $part )]; } else { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s %s', str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part @@ -491,12 +491,12 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } if (null !== $title) { - $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title))); + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > $limit = $markupLength - 4) { $titleLength = $limit; - $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, ''))); - $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); } $titleStart = intdiv($markupLength - $titleLength, 2); @@ -507,7 +507,7 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } } - $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); } /** @@ -517,7 +517,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string { $borders = $this->style->getBorderChars(); - return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** @@ -565,11 +565,11 @@ private function renderCell(array $row, int $column, string $cellFormat): string $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { - return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); + return \sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); - $content = sprintf($style->getCellRowContentFormat(), $cell); + $content = \sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { @@ -594,7 +594,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string $padType = $cell->getStyle()->getPadByAlign(); } - return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); + return \sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** @@ -691,7 +691,7 @@ private function fillNextRows(array $rows, int $line): array $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { - throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; @@ -836,7 +836,7 @@ private function calculateColumnsWidth(iterable $groups): void private function getColumnSeparatorWidth(): int { - return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column): int @@ -919,6 +919,6 @@ private function resolveStyle(TableStyle|string $name): TableStyle return $name; } - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } } diff --git a/Helper/TableCell.php b/Helper/TableCell.php index 1c4eeea20..ab8339204 100644 --- a/Helper/TableCell.php +++ b/Helper/TableCell.php @@ -30,7 +30,7 @@ public function __construct( ) { // check option names if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { diff --git a/Helper/TableCellStyle.php b/Helper/TableCellStyle.php index 49b97f853..af1a17e96 100644 --- a/Helper/TableCellStyle.php +++ b/Helper/TableCellStyle.php @@ -43,11 +43,11 @@ class TableCellStyle public function __construct(array $options = []) { if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { - throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); } $this->options = array_merge($this->options, $options); diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index 2ebbdf086..e0f426510 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -51,7 +51,7 @@ public function __construct(?array $argv = null, ?InputDefinition $definition = foreach ($argv as $arg) { if (!\is_scalar($arg) && !$arg instanceof \Stringable) { - throw new RuntimeException(sprintf('Argument values expected to be all scalars, got "%s".', get_debug_type($arg))); + throw new RuntimeException(\sprintf('Argument values expected to be all scalars, got "%s".', get_debug_type($arg))); } } @@ -125,7 +125,7 @@ private function parseShortOptionSet(string $name): void for ($i = 0; $i < $len; ++$i) { if (!$this->definition->hasShortcut($name[$i])) { $encoding = mb_detect_encoding($name, null, true); - throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); } $option = $this->definition->getOptionForShortcut($name[$i]); @@ -186,14 +186,14 @@ private function parseArgument(string $token): void if (\count($all)) { if ($symfonyCommandName) { - $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); } else { - $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); } } elseif ($symfonyCommandName) { - $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); } else { - $message = sprintf('No arguments expected, got "%s".', $token); + $message = \sprintf('No arguments expected, got "%s".', $token); } throw new RuntimeException($message); @@ -208,7 +208,7 @@ private function parseArgument(string $token): void private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -223,12 +223,12 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); if (null !== $value) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } $this->options[$optionName] = false; @@ -238,7 +238,7 @@ private function addLongOption(string $name, mixed $value): void $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) { @@ -254,7 +254,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isArray() && !$option->isValueOptional()) { diff --git a/Input/ArrayInput.php b/Input/ArrayInput.php index d27ff411e..7335632bf 100644 --- a/Input/ArrayInput.php +++ b/Input/ArrayInput.php @@ -135,7 +135,7 @@ protected function parse(): void private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -151,7 +151,7 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); @@ -164,7 +164,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isValueOptional()) { @@ -183,7 +183,7 @@ private function addLongOption(string $name, mixed $value): void private function addArgument(string|int $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; diff --git a/Input/Input.php b/Input/Input.php index 5a8b9a27a..d2881c60f 100644 --- a/Input/Input.php +++ b/Input/Input.php @@ -66,7 +66,7 @@ public function validate(): void $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); if (\count($missingArguments) > 0) { - throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } } @@ -88,7 +88,7 @@ public function getArguments(): array public function getArgument(string $name): mixed { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); @@ -97,7 +97,7 @@ public function getArgument(string $name): mixed public function setArgument(string $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; @@ -124,7 +124,7 @@ public function getOption(string $name): mixed } if (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); @@ -137,7 +137,7 @@ public function setOption(string $name, mixed $value): void return; } elseif (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } $this->options[$name] = $value; diff --git a/Input/InputArgument.php b/Input/InputArgument.php index a5d949277..6fbb64ed0 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -62,7 +62,7 @@ public function __construct( if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode >= (self::IS_ARRAY << 1) || $mode < 1) { - throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); } $this->mode = $mode; @@ -143,7 +143,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/Input/InputDefinition.php b/Input/InputDefinition.php index f27e29748..a8b006d48 100644 --- a/Input/InputDefinition.php +++ b/Input/InputDefinition.php @@ -97,15 +97,15 @@ public function addArguments(?array $arguments = []): void public function addArgument(InputArgument $argument): void { if (isset($this->arguments[$argument->getName()])) { - throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); } if (null !== $this->lastArrayArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); } if ($argument->isRequired() && null !== $this->lastOptionalArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); } if ($argument->isArray()) { @@ -129,7 +129,7 @@ public function addArgument(InputArgument $argument): void public function getArgument(string|int $name): InputArgument { if (!$this->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; @@ -217,16 +217,16 @@ public function addOptions(array $options = []): void public function addOption(InputOption $option): void { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if (isset($this->negations[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if ($option->getShortcut()) { foreach (explode('|', $option->getShortcut()) as $shortcut) { if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { - throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut)); + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); } } } @@ -241,7 +241,7 @@ public function addOption(InputOption $option): void if ($option->isNegatable()) { $negatedName = 'no-'.$option->getName(); if (isset($this->options[$negatedName])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName)); + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); } $this->negations[$negatedName] = $option->getName(); } @@ -255,7 +255,7 @@ public function addOption(InputOption $option): void public function getOption(string $name): InputOption { if (!$this->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); } return $this->options[$name]; @@ -329,7 +329,7 @@ public function getOptionDefaults(): array public function shortcutToName(string $shortcut): string { if (!isset($this->shortcuts[$shortcut])) { - throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); } return $this->shortcuts[$shortcut]; @@ -345,7 +345,7 @@ public function shortcutToName(string $shortcut): string public function negationToName(string $negation): string { if (!isset($this->negations[$negation])) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); } return $this->negations[$negation]; @@ -364,7 +364,7 @@ public function getSynopsis(bool $short = false): string foreach ($this->getOptions() as $option) { $value = ''; if ($option->acceptValue()) { - $value = sprintf( + $value = \sprintf( ' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), @@ -372,9 +372,9 @@ public function getSynopsis(bool $short = false): string ); } - $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; - $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : ''; - $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } diff --git a/Input/InputOption.php b/Input/InputOption.php index 617c348d5..25fb91782 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -99,7 +99,7 @@ public function __construct( if (null === $mode) { $mode = self::VALUE_NONE; } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { - throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -238,7 +238,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/Input/StringInput.php b/Input/StringInput.php index 835700143..a70f048f9 100644 --- a/Input/StringInput.php +++ b/Input/StringInput.php @@ -70,7 +70,7 @@ private function tokenize(string $input): array $token .= $match[1]; } else { // should never happen - throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); } $cursor += \strlen($match[0]); diff --git a/Logger/ConsoleLogger.php b/Logger/ConsoleLogger.php index ad6e49ce1..a6ef49ea9 100644 --- a/Logger/ConsoleLogger.php +++ b/Logger/ConsoleLogger.php @@ -63,7 +63,7 @@ public function __construct( public function log($level, $message, array $context = []): void { if (!isset($this->verbosityLevelMap[$level])) { - throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); } $output = $this->output; @@ -79,7 +79,7 @@ public function log($level, $message, array $context = []): void // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { - $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } diff --git a/Messenger/RunCommandMessageHandler.php b/Messenger/RunCommandMessageHandler.php index 1bc499494..0fdf7d017 100644 --- a/Messenger/RunCommandMessageHandler.php +++ b/Messenger/RunCommandMessageHandler.php @@ -41,7 +41,7 @@ public function __invoke(RunCommandMessage $message): RunCommandContext } if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { - throw new RunCommandFailedException(sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); } return new RunCommandContext($message, $exitCode, $output->fetch()); diff --git a/Output/AnsiColorMode.php b/Output/AnsiColorMode.php index ca40ffb79..dcdd1d5c4 100644 --- a/Output/AnsiColorMode.php +++ b/Output/AnsiColorMode.php @@ -51,7 +51,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string } if (6 !== \strlen($hexColor)) { - throw new InvalidArgumentException(sprintf('Invalid "#%s" color.', $hexColor)); + throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor)); } $color = hexdec($hexColor); @@ -63,7 +63,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string return match ($this) { self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), - self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b), + self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b), }; } diff --git a/Output/ConsoleSectionOutput.php b/Output/ConsoleSectionOutput.php index 09aa7fe99..44728dfd4 100644 --- a/Output/ConsoleSectionOutput.php +++ b/Output/ConsoleSectionOutput.php @@ -222,7 +222,7 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr if ($numberOfLinesToClear > 0) { // move cursor up n lines - parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false); + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), false); // erase to end of screen parent::doWrite("\x1b[0J", false); } diff --git a/Output/TrimmedBufferOutput.php b/Output/TrimmedBufferOutput.php index c1862a2bd..f0f950545 100644 --- a/Output/TrimmedBufferOutput.php +++ b/Output/TrimmedBufferOutput.php @@ -27,7 +27,7 @@ class TrimmedBufferOutput extends Output public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { - throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); } parent::__construct($verbosity, $decorated, $formatter); diff --git a/Question/ChoiceQuestion.php b/Question/ChoiceQuestion.php index 0ccad051c..d184ef76f 100644 --- a/Question/ChoiceQuestion.php +++ b/Question/ChoiceQuestion.php @@ -121,7 +121,7 @@ private function getDefaultValidator(): callable if ($multiselect) { // Check for a separated comma values if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { - throw new InvalidArgumentException(sprintf($errorMessage, $selected)); + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); } $selectedChoices = explode(',', (string) $selected); @@ -145,7 +145,7 @@ private function getDefaultValidator(): callable } if (\count($results) > 1) { - throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); } $result = array_search($value, $choices); @@ -161,7 +161,7 @@ private function getDefaultValidator(): callable } if (false === $result) { - throw new InvalidArgumentException(sprintf($errorMessage, $value)); + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); } // For associative choices, consistently return the key as string: diff --git a/Style/SymfonyStyle.php b/Style/SymfonyStyle.php index 19ad892ef..4cf62cdba 100644 --- a/Style/SymfonyStyle.php +++ b/Style/SymfonyStyle.php @@ -73,8 +73,8 @@ public function title(string $message): void { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -83,8 +83,8 @@ public function section(string $message): void { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -92,7 +92,7 @@ public function section(string $message): void public function listing(array $elements): void { $this->autoPrependText(); - $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); + $elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); @@ -104,7 +104,7 @@ public function text(string|array $message): void $messages = \is_array($message) ? array_values($message) : [$message]; foreach ($messages as $message) { - $this->writeln(sprintf(' %s', $message)); + $this->writeln(\sprintf(' %s', $message)); } } @@ -404,7 +404,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $lines = []; if (null !== $type) { - $type = sprintf('[%s] ', $type); + $type = \sprintf('[%s] ', $type); $indentLength = Helper::width($type); $lineIndentation = str_repeat(' ', $indentLength); } @@ -446,7 +446,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); if ($style) { - $line = sprintf('<%s>%s', $style, $line); + $line = \sprintf('<%s>%s', $style, $line); } } diff --git a/Tester/Constraint/CommandIsSuccessful.php b/Tester/Constraint/CommandIsSuccessful.php index 09c6194b9..d677c27aa 100644 --- a/Tester/Constraint/CommandIsSuccessful.php +++ b/Tester/Constraint/CommandIsSuccessful.php @@ -38,6 +38,6 @@ protected function additionalFailureDescription($other): string Command::INVALID => 'Command was invalid.', ]; - return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other); + return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); } } diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index d8e1ae8b9..4fd2466e0 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -637,7 +637,7 @@ public function testFindAlternativeCommands() } catch (\Exception $e) { $this->assertInstanceOf(CommandNotFoundException::class, $e, '->find() throws a CommandNotFoundException if command does not exist'); $this->assertSame([], $e->getAlternatives()); - $this->assertEquals(sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without alternatives'); + $this->assertEquals(\sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without alternatives'); } // Test if "bar1" command throw a "CommandNotFoundException" and does not contain @@ -648,7 +648,7 @@ public function testFindAlternativeCommands() } catch (\Exception $e) { $this->assertInstanceOf(CommandNotFoundException::class, $e, '->find() throws a CommandNotFoundException if command does not exist'); $this->assertSame(['afoobar1', 'foo:bar1'], $e->getAlternatives()); - $this->assertMatchesRegularExpression(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives'); + $this->assertMatchesRegularExpression(\sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives'); $this->assertMatchesRegularExpression('/afoobar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "afoobar1"'); $this->assertMatchesRegularExpression('/foo:bar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "foo:bar1"'); $this->assertDoesNotMatchRegularExpression('/foo:bar(?!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative'); @@ -967,7 +967,7 @@ public function testRenderAnonymousException() $application = new Application(); $application->setAutoExit(false); $application->register('foo')->setCode(function () { - throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); + throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); }); $tester = new ApplicationTester($application); @@ -993,7 +993,7 @@ public function testRenderExceptionStackTraceContainsRootException() $application = new Application(); $application->setAutoExit(false); $application->register('foo')->setCode(function () { - throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); + throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); }); $tester = new ApplicationTester($application); diff --git a/Tests/Command/CommandTest.php b/Tests/Command/CommandTest.php index f3e4b51d1..199c0c309 100644 --- a/Tests/Command/CommandTest.php +++ b/Tests/Command/CommandTest.php @@ -139,7 +139,7 @@ public function testGetNamespaceGetNameSetName() public function testInvalidCommandNames($name) { $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage(sprintf('Command name "%s" is invalid.', $name)); + $this->expectExceptionMessage(\sprintf('Command name "%s" is invalid.', $name)); (new \TestCommand())->setName($name); } diff --git a/Tests/Descriptor/AbstractDescriptorTestCase.php b/Tests/Descriptor/AbstractDescriptorTestCase.php index 1f813048d..93658f4be 100644 --- a/Tests/Descriptor/AbstractDescriptorTestCase.php +++ b/Tests/Descriptor/AbstractDescriptorTestCase.php @@ -87,7 +87,7 @@ protected static function getDescriptionTestData(array $objects) { $data = []; foreach ($objects as $name => $object) { - $description = file_get_contents(sprintf('%s/../Fixtures/%s.%s', __DIR__, $name, static::getFormat())); + $description = file_get_contents(\sprintf('%s/../Fixtures/%s.%s', __DIR__, $name, static::getFormat())); $data[] = [$object, $description]; } diff --git a/Tests/Helper/ProgressIndicatorTest.php b/Tests/Helper/ProgressIndicatorTest.php index 7f7dbc0a0..8e2e10e37 100644 --- a/Tests/Helper/ProgressIndicatorTest.php +++ b/Tests/Helper/ProgressIndicatorTest.php @@ -179,6 +179,6 @@ protected function generateOutput($expected) { $count = substr_count($expected, "\n"); - return "\x0D\x1B[2K".($count ? sprintf("\033[%dA", $count) : '').$expected; + return "\x0D\x1B[2K".($count ? \sprintf("\033[%dA", $count) : '').$expected; } } diff --git a/Tests/Input/InputDefinitionTest.php b/Tests/Input/InputDefinitionTest.php index 470f3ca74..4479f4403 100644 --- a/Tests/Input/InputDefinitionTest.php +++ b/Tests/Input/InputDefinitionTest.php @@ -113,7 +113,7 @@ public function testRequiredArgumentCannotFollowAnOptionalOne() { $this->initializeArguments(); $this->expectException(\LogicException::class); - $this->expectExceptionMessage(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $this->foo2->getName(), $this->foo->getName())); + $this->expectExceptionMessage(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $this->foo2->getName(), $this->foo->getName())); $definition = new InputDefinition(); $definition->addArgument($this->foo); diff --git a/Tests/Output/ConsoleSectionOutputTest.php b/Tests/Output/ConsoleSectionOutputTest.php index e50f8d54a..6d2fa6c3c 100644 --- a/Tests/Output/ConsoleSectionOutputTest.php +++ b/Tests/Output/ConsoleSectionOutputTest.php @@ -44,7 +44,7 @@ public function testClearAll() $output->clear(); rewind($output->getStream()); - $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); + $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.\sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); } public function testClearNumberOfLines() @@ -56,7 +56,7 @@ public function testClearNumberOfLines() $output->clear(2); rewind($output->getStream()); - $this->assertEquals("Foo\nBar\nBaz\nFooBar".\PHP_EOL.sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); + $this->assertEquals("Foo\nBar\nBaz\nFooBar".\PHP_EOL.\sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); } public function testClearNumberOfLinesWithMultipleSections() @@ -197,7 +197,7 @@ public function testOverwriteMultipleLines() $output->overwrite('Bar'); rewind($output->getStream()); - $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.'Baz'.\PHP_EOL.sprintf("\x1b[%dA", 3)."\x1b[0J".'Bar'.\PHP_EOL, stream_get_contents($output->getStream())); + $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.'Baz'.\PHP_EOL.\sprintf("\x1b[%dA", 3)."\x1b[0J".'Bar'.\PHP_EOL, stream_get_contents($output->getStream())); } public function testAddingMultipleSections() diff --git a/Tests/Question/ConfirmationQuestionTest.php b/Tests/Question/ConfirmationQuestionTest.php index 44f4c870b..bd11047b3 100644 --- a/Tests/Question/ConfirmationQuestionTest.php +++ b/Tests/Question/ConfirmationQuestionTest.php @@ -26,7 +26,7 @@ public function testDefaultRegexUsecases($default, $answers, $expected, $message foreach ($answers as $answer) { $normalizer = $sut->getNormalizer(); $actual = $normalizer($answer); - $this->assertEquals($expected, $actual, sprintf($message, $answer)); + $this->assertEquals($expected, $actual, \sprintf($message, $answer)); } } From f63a2ee79c1e330a378bb8262a02c7497f1662be Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 16 Jun 2024 17:17:26 +0200 Subject: [PATCH 29/59] chore: CS fixes --- Helper/ProgressIndicator.php | 1 - Tests/Input/InputDefinitionTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Helper/ProgressIndicator.php b/Helper/ProgressIndicator.php index 969d83539..4a9987a36 100644 --- a/Helper/ProgressIndicator.php +++ b/Helper/ProgressIndicator.php @@ -54,7 +54,6 @@ public function __construct( private int $indicatorChangeInterval = 100, ?array $indicatorValues = null, ) { - $format ??= $this->determineBestFormat(); $indicatorValues ??= ['-', '\\', '|', '/']; $indicatorValues = array_values($indicatorValues); diff --git a/Tests/Input/InputDefinitionTest.php b/Tests/Input/InputDefinitionTest.php index 4479f4403..a3fd3e2ea 100644 --- a/Tests/Input/InputDefinitionTest.php +++ b/Tests/Input/InputDefinitionTest.php @@ -179,7 +179,7 @@ public function testGetArgumentDefaults() new InputArgument('foo1', InputArgument::OPTIONAL), new InputArgument('foo2', InputArgument::OPTIONAL, '', 'default'), new InputArgument('foo3', InputArgument::OPTIONAL | InputArgument::IS_ARRAY), - // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', [1, 2]), + // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', [1, 2]), ]); $this->assertEquals(['foo1' => null, 'foo2' => 'default', 'foo3' => []], $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); From 5ed7b6cee62e34c6bdba8fb2fb1a4cbb4e0a15c3 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Fri, 28 Jun 2024 15:26:34 +0700 Subject: [PATCH 30/59] Add return type to __toString() methods --- Completion/CompletionInput.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Completion/CompletionInput.php b/Completion/CompletionInput.php index 7ba41c083..27c1c9105 100644 --- a/Completion/CompletionInput.php +++ b/Completion/CompletionInput.php @@ -226,7 +226,7 @@ private function isCursorFree(): bool return $this->currentIndex >= $nrOfTokens; } - public function __toString() + public function __toString(): string { $str = ''; foreach ($this->tokens as $i => $token) { From d36a5fe1861fafe285be56e2aede1d19fc648502 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 6 Jul 2024 09:57:16 +0200 Subject: [PATCH 31/59] Update .gitattributes --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 84c7add05..14c3c3594 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore From 22e3436515bb5719c77a502cfd8cd5972e09805c Mon Sep 17 00:00:00 2001 From: Quynh Nguyen Date: Thu, 18 Jul 2024 14:04:31 +0700 Subject: [PATCH 32/59] [Console] Remove a redundant check in `ErrorListener` --- EventListener/ErrorListener.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/EventListener/ErrorListener.php b/EventListener/ErrorListener.php index 49915a498..87b0d70f1 100644 --- a/EventListener/ErrorListener.php +++ b/EventListener/ErrorListener.php @@ -75,19 +75,15 @@ public static function getSubscribedEvents(): array ]; } - private static function getInputString(ConsoleEvent $event): ?string + private static function getInputString(ConsoleEvent $event): string { $commandName = $event->getCommand()?->getName(); - $input = $event->getInput(); + $inputString = (string) $event->getInput(); - if ($input instanceof \Stringable) { - if ($commandName) { - return str_replace(["'$commandName'", "\"$commandName\""], $commandName, (string) $input); - } - - return (string) $input; + if ($commandName) { + return str_replace(["'$commandName'", "\"$commandName\""], $commandName, $inputString); } - return $commandName; + return $inputString; } } From f807c5379d2e4068c57ada1c5ee9b7a5c32cd64f Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 22 Jul 2024 09:20:55 +0200 Subject: [PATCH 33/59] Replace `TestCase::assertTrue(true)` with `TestCase::expectNotToPerformAssertions()` --- Tests/Command/CompleteCommandTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Command/CompleteCommandTest.php b/Tests/Command/CompleteCommandTest.php index 0f64fbc8e..27b998b36 100644 --- a/Tests/Command/CompleteCommandTest.php +++ b/Tests/Command/CompleteCommandTest.php @@ -53,6 +53,8 @@ public function testUnsupportedShellOption() public function testAdditionalShellSupport() { + $this->expectNotToPerformAssertions(); + $this->command = new CompleteCommand(['supported' => BashCompletionOutput::class]); $this->command->setApplication($this->application); $this->tester = new CommandTester($this->command); @@ -61,8 +63,6 @@ public function testAdditionalShellSupport() // verify that the default set of shells is still supported $this->execute(['--shell' => 'bash', '--current' => '1', '--input' => ['bin/console']]); - - $this->assertTrue(true); } /** From 43b48b29222efc89b65032409d6eb4d0c2883c34 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 22 Jul 2024 10:27:43 +0200 Subject: [PATCH 34/59] Use CPP where possible --- CI/GithubActionReporter.php | 8 +++----- Formatter/OutputFormatter.php | 9 ++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/CI/GithubActionReporter.php b/CI/GithubActionReporter.php index 28112c2a2..952d380d5 100644 --- a/CI/GithubActionReporter.php +++ b/CI/GithubActionReporter.php @@ -20,8 +20,6 @@ */ class GithubActionReporter { - private OutputInterface $output; - /** * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85 */ @@ -42,9 +40,9 @@ class GithubActionReporter ',' => '%2C', ]; - public function __construct(OutputInterface $output) - { - $this->output = $output; + public function __construct( + private OutputInterface $output, + ) { } public static function isGithubActionEnvironment(): bool diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php index 1f3d04a2e..3c8c287e8 100644 --- a/Formatter/OutputFormatter.php +++ b/Formatter/OutputFormatter.php @@ -23,7 +23,6 @@ */ class OutputFormatter implements WrappableOutputFormatterInterface { - private bool $decorated; private array $styles = []; private OutputFormatterStyleStack $styleStack; @@ -67,10 +66,10 @@ public static function escapeTrailingBackslash(string $text): string * * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances */ - public function __construct(bool $decorated = false, array $styles = []) - { - $this->decorated = $decorated; - + public function __construct( + private bool $decorated = false, + array $styles = [], + ) { $this->setStyle('error', new OutputFormatterStyle('white', 'red')); $this->setStyle('info', new OutputFormatterStyle('green')); $this->setStyle('comment', new OutputFormatterStyle('yellow')); From 8b3ee1c3ef9de3ade24c0ccb42377c334acd311f Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 19 Jul 2024 13:24:25 +0200 Subject: [PATCH 35/59] [Cache][Config][Console][DependencyInjection][FrameworkBundle] Remove dead code and useless casts --- Command/CompleteCommand.php | 8 ++++---- Descriptor/ReStructuredTextDescriptor.php | 2 +- Descriptor/XmlDescriptor.php | 8 +++----- Output/AnsiColorMode.php | 2 +- Output/TrimmedBufferOutput.php | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Command/CompleteCommand.php b/Command/CompleteCommand.php index df0cddabb..15eeea16a 100644 --- a/Command/CompleteCommand.php +++ b/Command/CompleteCommand.php @@ -98,13 +98,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int '', ''.date('Y-m-d H:i:s').'', 'Input: ("|" indicates the cursor position)', - ' '.(string) $completionInput, + ' '.$completionInput, 'Command:', - ' '.(string) implode(' ', $_SERVER['argv']), + ' '.implode(' ', $_SERVER['argv']), 'Messages:', ]); - $command = $this->findCommand($completionInput, $output); + $command = $this->findCommand($completionInput); if (null === $command) { $this->log(' No command found, completing using the Application class.'); @@ -185,7 +185,7 @@ private function createCompletionInput(InputInterface $input): CompletionInput return $completionInput; } - private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command + private function findCommand(CompletionInput $completionInput): ?Command { try { $inputName = $completionInput->getFirstArgument(); diff --git a/Descriptor/ReStructuredTextDescriptor.php b/Descriptor/ReStructuredTextDescriptor.php index 462b9bb0b..cbf49d879 100644 --- a/Descriptor/ReStructuredTextDescriptor.php +++ b/Descriptor/ReStructuredTextDescriptor.php @@ -92,7 +92,7 @@ protected function describeInputOption(InputOption $option, array $options = []) protected function describeInputDefinition(InputDefinition $definition, array $options = []): void { if ($showArguments = ((bool) $definition->getArguments())) { - $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9))."\n\n"; + $this->write("Arguments\n".str_repeat($this->subsubsectionChar, 9)); foreach ($definition->getArguments() as $argument) { $this->write("\n\n"); $this->describeInputArgument($argument); diff --git a/Descriptor/XmlDescriptor.php b/Descriptor/XmlDescriptor.php index 8e44c88c4..00055557c 100644 --- a/Descriptor/XmlDescriptor.php +++ b/Descriptor/XmlDescriptor.php @@ -208,11 +208,9 @@ private function getInputOptionDocument(InputOption $option): \DOMDocument $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [var_export($option->getDefault(), true)] : ($option->getDefault() ? [$option->getDefault()] : [])); $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); - if ($defaults) { - foreach ($defaults as $default) { - $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); - $defaultXML->appendChild($dom->createTextNode($default)); - } + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); } } diff --git a/Output/AnsiColorMode.php b/Output/AnsiColorMode.php index dcdd1d5c4..cde0539fe 100644 --- a/Output/AnsiColorMode.php +++ b/Output/AnsiColorMode.php @@ -62,7 +62,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string return match ($this) { self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), - self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), + self::Ansi8 => '8;5;'.$this->convertFromRGB($r, $g, $b), self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b), }; } diff --git a/Output/TrimmedBufferOutput.php b/Output/TrimmedBufferOutput.php index f0f950545..33db072c5 100644 --- a/Output/TrimmedBufferOutput.php +++ b/Output/TrimmedBufferOutput.php @@ -53,6 +53,6 @@ protected function doWrite(string $message, bool $newline): void $this->buffer .= \PHP_EOL; } - $this->buffer = substr($this->buffer, 0 - $this->maxLength); + $this->buffer = substr($this->buffer, -$this->maxLength); } } From d48400b51d1bd1de2513afc097b2b6f3deaa88ab Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 31 Jul 2024 16:13:26 +0200 Subject: [PATCH 36/59] Remove unused code and unnecessary `else` branches --- Application.php | 2 -- Helper/ProgressBar.php | 2 +- Helper/ProgressIndicator.php | 2 +- Input/ArgvInput.php | 4 ++-- Output/AnsiColorMode.php | 10 +++++----- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Application.php b/Application.php index aa4af5c58..d90600c5e 100644 --- a/Application.php +++ b/Application.php @@ -383,8 +383,6 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) { $suggestions->suggestOptions($this->getDefinition()->getOptions()); - - return; } } diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index 5f1a32bc9..2dac1dfa2 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -610,7 +610,7 @@ private function buildLine(): string { \assert(null !== $this->format); - $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; + $regex = '{%([a-z\-_]+)(?:\:([^%]+))?%}i'; $callback = function ($matches) { if ($formatter = $this->getPlaceholderFormatter($matches[1])) { $text = $formatter($this, $this->output); diff --git a/Helper/ProgressIndicator.php b/Helper/ProgressIndicator.php index 4a9987a36..d06897d85 100644 --- a/Helper/ProgressIndicator.php +++ b/Helper/ProgressIndicator.php @@ -171,7 +171,7 @@ private function display(): void return; } - $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) { + $this->overwrite(preg_replace_callback('{%([a-z\-_]+)(?:\:([^%]+))?%}i', function ($matches) { if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) { return $formatter($this); } diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index e0f426510..fe25b861a 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -133,9 +133,9 @@ private function parseShortOptionSet(string $name): void $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1)); break; - } else { - $this->addLongOption($option->getName(), null); } + + $this->addLongOption($option->getName(), null); } } diff --git a/Output/AnsiColorMode.php b/Output/AnsiColorMode.php index cde0539fe..0e1422a27 100644 --- a/Output/AnsiColorMode.php +++ b/Output/AnsiColorMode.php @@ -96,11 +96,11 @@ private function degradeHexColorToAnsi8(int $r, int $g, int $b): int } return (int) round(($r - 8) / 247 * 24) + 232; - } else { - return 16 + - (36 * (int) round($r / 255 * 5)) + - (6 * (int) round($g / 255 * 5)) + - (int) round($b / 255 * 5); } + + return 16 + + (36 * (int) round($r / 255 * 5)) + + (6 * (int) round($g / 255 * 5)) + + (int) round($b / 255 * 5); } } From 7d6b78e000021ea69c8bf425cbbac326bf08720c Mon Sep 17 00:00:00 2001 From: Roy de Vos Burchart Date: Thu, 1 Aug 2024 17:21:17 +0200 Subject: [PATCH 37/59] Code style change in `@PER-CS2.0` affecting `@Symfony` (parentheses for anonymous classes) --- Tests/ApplicationTest.php | 4 ++-- Tests/Command/SingleCommandApplicationTest.php | 2 +- Tests/Messenger/RunCommandMessageHandlerTest.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index 84684bf84..a1884ff31 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -965,7 +965,7 @@ public function testRenderAnonymousException() $application = new Application(); $application->setAutoExit(false); $application->register('foo')->setCode(function () { - throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); + throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class {})::class)); }); $tester = new ApplicationTester($application); @@ -991,7 +991,7 @@ public function testRenderExceptionStackTraceContainsRootException() $application = new Application(); $application->setAutoExit(false); $application->register('foo')->setCode(function () { - throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); + throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class {})::class)); }); $tester = new ApplicationTester($application); diff --git a/Tests/Command/SingleCommandApplicationTest.php b/Tests/Command/SingleCommandApplicationTest.php index 8fae4876b..98000c0a7 100644 --- a/Tests/Command/SingleCommandApplicationTest.php +++ b/Tests/Command/SingleCommandApplicationTest.php @@ -21,7 +21,7 @@ class SingleCommandApplicationTest extends TestCase { public function testRun() { - $command = new class() extends SingleCommandApplication { + $command = new class extends SingleCommandApplication { protected function execute(InputInterface $input, OutputInterface $output): int { return 0; diff --git a/Tests/Messenger/RunCommandMessageHandlerTest.php b/Tests/Messenger/RunCommandMessageHandlerTest.php index adc31e0ec..58b33d565 100644 --- a/Tests/Messenger/RunCommandMessageHandlerTest.php +++ b/Tests/Messenger/RunCommandMessageHandlerTest.php @@ -86,7 +86,7 @@ private function createApplicationWithCommand(): Application $application = new Application(); $application->setAutoExit(false); $application->addCommands([ - new class() extends Command { + new class extends Command { public function configure(): void { $this From 7884dc76c55a618ca70cf3a5919277b053f703bb Mon Sep 17 00:00:00 2001 From: Artfaith Date: Fri, 19 Jul 2024 15:07:04 +0200 Subject: [PATCH 38/59] [PhpUnitBridge][Console][VarDumper] Add support for `FORCE_COLOR` environment variable --- CHANGELOG.md | 5 +++++ Output/StreamOutput.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25d7f7179..a959f65d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Add support for `FORCE_COLOR` environment variable + 7.1 --- diff --git a/Output/StreamOutput.php b/Output/StreamOutput.php index 84a7fa734..f77b49db6 100644 --- a/Output/StreamOutput.php +++ b/Output/StreamOutput.php @@ -94,6 +94,11 @@ protected function hasColorSupport(): bool return false; } + // Follow https://force-color.org/ + if ('' !== (($_SERVER['FORCE_COLOR'] ?? getenv('FORCE_COLOR'))[0] ?? '')) { + return true; + } + // Detect msysgit/mingw and assume this is a tty because detection // does not work correctly, see https://github.com/composer/composer/issues/9690 if (!@stream_isatty($this->stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { From ee7ee22b1dabcff731b7d79d3633c96251ad8404 Mon Sep 17 00:00:00 2001 From: Will Rowe Date: Fri, 23 Aug 2024 11:21:30 -0400 Subject: [PATCH 39/59] [Console][Process] Add `$verbosity` argument to `mustRun` helper method --- CHANGELOG.md | 1 + Helper/ProcessHelper.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a959f65d8..5a3dd745a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add support for `FORCE_COLOR` environment variable + * Add `verbosity` argument to `mustRun` process helper method 7.1 --- diff --git a/Helper/ProcessHelper.php b/Helper/ProcessHelper.php index ae55a83c2..4a8cfc9d9 100644 --- a/Helper/ProcessHelper.php +++ b/Helper/ProcessHelper.php @@ -94,9 +94,9 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error * * @see run() */ - public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null): Process + public function mustRun(OutputInterface $output, array|Process $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process { - $process = $this->run($output, $cmd, $error, $callback); + $process = $this->run($output, $cmd, $error, $callback, $verbosity); if (!$process->isSuccessful()) { throw new ProcessFailedException($process); From 07d683cda368a88df91d231aa97dfdfa02c4f3ac Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 5 Sep 2024 08:55:30 +0200 Subject: [PATCH 40/59] no longer use the internal TestFailure class --- .../Tester/Constraint/CommandIsSuccessfulTest.php | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Tests/Tester/Constraint/CommandIsSuccessfulTest.php b/Tests/Tester/Constraint/CommandIsSuccessfulTest.php index 7a2b4c719..61ab5d0f8 100644 --- a/Tests/Tester/Constraint/CommandIsSuccessfulTest.php +++ b/Tests/Tester/Constraint/CommandIsSuccessfulTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; -use PHPUnit\Framework\TestFailure; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful; @@ -35,16 +34,9 @@ public function testUnsuccessfulCommand(string $expectedException, int $exitCode { $constraint = new CommandIsSuccessful(); - try { - $constraint->evaluate($exitCode); - } catch (ExpectationFailedException $e) { - $this->assertStringContainsString('Failed asserting that the command is successful.', TestFailure::exceptionToString($e)); - $this->assertStringContainsString($expectedException, TestFailure::exceptionToString($e)); - - return; - } - - $this->fail(); + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessageMatches('/Failed asserting that the command is successful\..*'.$expectedException.'/s'); + $constraint->evaluate($exitCode); } public static function providesUnsuccessful(): iterable From e57e6e0355bf231a6befd5d8ff2940308f0005eb Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Thu, 19 Sep 2024 14:29:18 +0200 Subject: [PATCH 41/59] [Console] Add silent verbosity mode suppressing all output, including errors --- Application.php | 13 ++- CHANGELOG.md | 2 + Descriptor/ReStructuredTextDescriptor.php | 1 + Output/NullOutput.php | 9 +- Output/Output.php | 10 ++- Output/OutputInterface.php | 3 + Style/OutputStyle.php | 6 ++ Tests/ApplicationTest.php | 5 +- Tests/Command/CompleteCommandTest.php | 4 +- Tests/Command/ListCommandTest.php | 3 +- Tests/Fixtures/application_1.json | 44 +++++++++- Tests/Fixtures/application_1.md | 36 +++++++- Tests/Fixtures/application_1.txt | 3 +- Tests/Fixtures/application_1.xml | 20 ++++- Tests/Fixtures/application_2.json | 88 +++++++++++++++++-- Tests/Fixtures/application_2.md | 72 +++++++++++++-- Tests/Fixtures/application_2.txt | 3 +- Tests/Fixtures/application_2.xml | 40 +++++++-- .../application_filtered_namespace.txt | 3 +- Tests/Fixtures/application_mbstring.md | 48 +++++++++- Tests/Fixtures/application_mbstring.txt | 3 +- Tests/Fixtures/application_run1.txt | 3 +- Tests/Fixtures/application_run2.txt | 3 +- Tests/Fixtures/application_run3.txt | 3 +- Tests/Fixtures/application_run5.txt | 3 +- Tests/Output/NullOutputTest.php | 14 ++- Tests/Output/OutputTest.php | 1 + Tests/phpt/single_application/help_name.phpt | 3 +- 28 files changed, 385 insertions(+), 61 deletions(-) diff --git a/Application.php b/Application.php index d90600c5e..140ea5d72 100644 --- a/Application.php +++ b/Application.php @@ -913,6 +913,9 @@ protected function configureIO(InputInterface $input, OutputInterface $output): } switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) { + case -2: + $output->setVerbosity(OutputInterface::VERBOSITY_SILENT); + break; case -1: $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); break; @@ -930,7 +933,10 @@ protected function configureIO(InputInterface $input, OutputInterface $output): break; } - if (true === $input->hasParameterOption(['--quiet', '-q'], true)) { + if (true === $input->hasParameterOption(['--silent'], true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_SILENT); + $shellVerbosity = -2; + } elseif (true === $input->hasParameterOption(['--quiet', '-q'], true)) { $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); $shellVerbosity = -1; } else { @@ -946,7 +952,7 @@ protected function configureIO(InputInterface $input, OutputInterface $output): } } - if (-1 === $shellVerbosity) { + if (0 > $shellVerbosity) { $input->setInteractive(false); } @@ -1082,7 +1088,8 @@ protected function getDefaultInputDefinition(): InputDefinition return new InputDefinition([ new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the '.$this->defaultCommand.' command'), - new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), + new InputOption('--silent', null, InputOption::VALUE_NONE, 'Do not output any message'), + new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Only errors are displayed. All other output is suppressed'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a3dd745a..e1581b5d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * Add support for `FORCE_COLOR` environment variable * Add `verbosity` argument to `mustRun` process helper method + * [BC BREAK] Add silent verbosity (`--silent`/`SHELL_VERBOSITY=-2`) to suppress all output, including errors + * Add `OutputInterface::isSilent()`, `Output::isSilent()`, `OutputStyle::isSilent()` methods 7.1 --- diff --git a/Descriptor/ReStructuredTextDescriptor.php b/Descriptor/ReStructuredTextDescriptor.php index cbf49d879..d2dde6fba 100644 --- a/Descriptor/ReStructuredTextDescriptor.php +++ b/Descriptor/ReStructuredTextDescriptor.php @@ -217,6 +217,7 @@ private function getNonDefaultOptions(InputDefinition $definition): array { $globalOptions = [ 'help', + 'silent', 'quiet', 'verbose', 'version', diff --git a/Output/NullOutput.php b/Output/NullOutput.php index 40ae33282..8bec706d4 100644 --- a/Output/NullOutput.php +++ b/Output/NullOutput.php @@ -54,14 +54,19 @@ public function setVerbosity(int $level): void public function getVerbosity(): int { - return self::VERBOSITY_QUIET; + return self::VERBOSITY_SILENT; } - public function isQuiet(): bool + public function isSilent(): bool { return true; } + public function isQuiet(): bool + { + return false; + } + public function isVerbose(): bool { return false; diff --git a/Output/Output.php b/Output/Output.php index 2bb105748..32e6cb241 100644 --- a/Output/Output.php +++ b/Output/Output.php @@ -17,13 +17,14 @@ /** * Base class for output classes. * - * There are five levels of verbosity: + * There are six levels of verbosity: * * * normal: no option passed (normal output) * * verbose: -v (more output) * * very verbose: -vv (highly extended output) * * debug: -vvv (all debug output) - * * quiet: -q (no output) + * * quiet: -q (only output errors) + * * silent: --silent (no output) * * @author Fabien Potencier */ @@ -74,6 +75,11 @@ public function getVerbosity(): int return $this->verbosity; } + public function isSilent(): bool + { + return self::VERBOSITY_SILENT === $this->verbosity; + } + public function isQuiet(): bool { return self::VERBOSITY_QUIET === $this->verbosity; diff --git a/Output/OutputInterface.php b/Output/OutputInterface.php index 41315fbf2..969a3b022 100644 --- a/Output/OutputInterface.php +++ b/Output/OutputInterface.php @@ -17,9 +17,12 @@ * OutputInterface is the interface implemented by all Output classes. * * @author Fabien Potencier + * + * @method bool isSilent() */ interface OutputInterface { + public const VERBOSITY_SILENT = 8; public const VERBOSITY_QUIET = 16; public const VERBOSITY_NORMAL = 32; public const VERBOSITY_VERBOSE = 64; diff --git a/Style/OutputStyle.php b/Style/OutputStyle.php index 9f62ea312..89a3a4177 100644 --- a/Style/OutputStyle.php +++ b/Style/OutputStyle.php @@ -78,6 +78,12 @@ public function getFormatter(): OutputFormatterInterface return $this->output->getFormatter(); } + public function isSilent(): bool + { + // @deprecated since Symfony 7.2, change to $this->output->isSilent() in 8.0 + return method_exists($this->output, 'isSilent') ? $this->output->isSilent() : self::VERBOSITY_SILENT === $this->output->getVerbosity(); + } + public function isQuiet(): bool { return $this->output->isQuiet(); diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index a1884ff31..0fa10d85a 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -851,12 +851,15 @@ public function testRenderException() putenv('COLUMNS=120'); $tester = new ApplicationTester($application); - $tester->run(['command' => 'foo'], ['decorated' => false, 'capture_stderr_separately' => true]); + $tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_QUIET, 'capture_stderr_separately' => true]); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exception'); $tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE, 'capture_stderr_separately' => true]); $this->assertStringContainsString('Exception trace', $tester->getErrorOutput(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose'); + $tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_SILENT, 'capture_stderr_separately' => true]); + $this->assertSame('', $tester->getErrorOutput(true), '->renderException() renders nothing in SILENT verbosity'); + $tester->run(['command' => 'list', '--foo' => true], ['decorated' => false, 'capture_stderr_separately' => true]); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getErrorOutput(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command'); diff --git a/Tests/Command/CompleteCommandTest.php b/Tests/Command/CompleteCommandTest.php index 27b998b36..75519eb49 100644 --- a/Tests/Command/CompleteCommandTest.php +++ b/Tests/Command/CompleteCommandTest.php @@ -119,9 +119,9 @@ public function testCompleteCommandInputDefinition(array $input, array $suggesti public static function provideCompleteCommandInputDefinitionInputs() { - yield 'definition' => [['bin/console', 'hello', '-'], ['--help', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']]; + yield 'definition' => [['bin/console', 'hello', '-'], ['--help', '--silent', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']]; yield 'custom' => [['bin/console', 'hello'], ['Fabien', 'Robin', 'Wouter']]; - yield 'definition-aliased' => [['bin/console', 'ahoy', '-'], ['--help', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']]; + yield 'definition-aliased' => [['bin/console', 'ahoy', '-'], ['--help', '--silent', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']]; yield 'custom-aliased' => [['bin/console', 'ahoy'], ['Fabien', 'Robin', 'Wouter']]; } diff --git a/Tests/Command/ListCommandTest.php b/Tests/Command/ListCommandTest.php index 20dfa8d30..a6ffc8ab5 100644 --- a/Tests/Command/ListCommandTest.php +++ b/Tests/Command/ListCommandTest.php @@ -80,7 +80,8 @@ public function testExecuteListsCommandsOrder() Options: -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_1.json b/Tests/Fixtures/application_1.json index bd0bd94c7..1477659ad 100644 --- a/Tests/Fixtures/application_1.json +++ b/Tests/Fixtures/application_1.json @@ -29,13 +29,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -150,13 +159,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -262,13 +280,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -365,13 +392,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { diff --git a/Tests/Fixtures/application_1.md b/Tests/Fixtures/application_1.md index bb722c077..79d9b27aa 100644 --- a/Tests/Fixtures/application_1.md +++ b/Tests/Fixtures/application_1.md @@ -48,7 +48,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -58,6 +58,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -159,7 +169,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -169,6 +179,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -286,7 +306,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -296,6 +316,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug diff --git a/Tests/Fixtures/application_1.txt b/Tests/Fixtures/application_1.txt index f72f43a07..7fce7ce52 100644 --- a/Tests/Fixtures/application_1.txt +++ b/Tests/Fixtures/application_1.txt @@ -5,7 +5,8 @@ Console Tool Options: -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_1.xml b/Tests/Fixtures/application_1.xml index d109e055f..d726cee35 100644 --- a/Tests/Fixtures/application_1.xml +++ b/Tests/Fixtures/application_1.xml @@ -32,9 +32,12 @@ - + @@ -71,9 +74,12 @@ - + @@ -126,9 +132,12 @@ - + @@ -188,9 +197,12 @@ - + diff --git a/Tests/Fixtures/application_2.json b/Tests/Fixtures/application_2.json index b3eb10bda..4a6f411f5 100644 --- a/Tests/Fixtures/application_2.json +++ b/Tests/Fixtures/application_2.json @@ -33,13 +33,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -154,13 +163,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -266,13 +284,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -369,13 +396,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -457,13 +493,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -553,13 +598,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -630,13 +684,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { @@ -709,13 +772,22 @@ "description": "Display help for the given command. When no command is given display help for the list command", "default": false }, + "silent": { + "name": "--silent", + "shortcut": "", + "accept_value": false, + "is_value_required": false, + "is_multiple": false, + "description": "Do not output any message", + "default": false + }, "quiet": { "name": "--quiet", "shortcut": "-q", "accept_value": false, "is_value_required": false, "is_multiple": false, - "description": "Do not output any message", + "description": "Only errors are displayed. All other output is suppressed", "default": false }, "verbose": { diff --git a/Tests/Fixtures/application_2.md b/Tests/Fixtures/application_2.md index d4802c747..37e6c28fc 100644 --- a/Tests/Fixtures/application_2.md +++ b/Tests/Fixtures/application_2.md @@ -61,7 +61,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -71,6 +71,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -172,7 +182,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -182,6 +192,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -299,7 +319,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -309,6 +329,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -374,7 +404,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -384,6 +414,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -465,7 +505,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -475,6 +515,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -537,7 +587,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -547,6 +597,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug diff --git a/Tests/Fixtures/application_2.txt b/Tests/Fixtures/application_2.txt index aed535fa4..1725b5fa6 100644 --- a/Tests/Fixtures/application_2.txt +++ b/Tests/Fixtures/application_2.txt @@ -5,7 +5,8 @@ My Symfony application v1.0 Options: -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_2.xml b/Tests/Fixtures/application_2.xml index 6ee45c1fa..dd4b1800a 100644 --- a/Tests/Fixtures/application_2.xml +++ b/Tests/Fixtures/application_2.xml @@ -32,9 +32,12 @@ - + @@ -71,9 +74,12 @@ - + @@ -126,9 +132,12 @@ - + @@ -188,9 +197,12 @@ - + @@ -221,9 +233,12 @@ - + @@ -262,9 +277,12 @@ - + @@ -293,9 +311,12 @@ - + @@ -326,9 +347,12 @@ - + diff --git a/Tests/Fixtures/application_filtered_namespace.txt b/Tests/Fixtures/application_filtered_namespace.txt index c24da0bbc..762a7f68d 100644 --- a/Tests/Fixtures/application_filtered_namespace.txt +++ b/Tests/Fixtures/application_filtered_namespace.txt @@ -5,7 +5,8 @@ My Symfony application v1.0 Options: -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_mbstring.md b/Tests/Fixtures/application_mbstring.md index e7bc69c71..5e31b7ef4 100644 --- a/Tests/Fixtures/application_mbstring.md +++ b/Tests/Fixtures/application_mbstring.md @@ -52,7 +52,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -62,6 +62,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -163,7 +173,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -173,6 +183,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -290,7 +310,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -300,6 +320,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug @@ -381,7 +411,7 @@ Display help for the given command. When no command is given display help for th * Is negatable: no * Default: `false` -#### `--quiet|-q` +#### `--silent` Do not output any message @@ -391,6 +421,16 @@ Do not output any message * Is negatable: no * Default: `false` +#### `--quiet|-q` + +Only errors are displayed. All other output is suppressed + +* Accept value: no +* Is value required: no +* Is multiple: no +* Is negatable: no +* Default: `false` + #### `--verbose|-v|-vv|-vvv` Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug diff --git a/Tests/Fixtures/application_mbstring.txt b/Tests/Fixtures/application_mbstring.txt index 73a47fff4..e904ddf05 100644 --- a/Tests/Fixtures/application_mbstring.txt +++ b/Tests/Fixtures/application_mbstring.txt @@ -5,7 +5,8 @@ MbString åpplicätion Options: -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_run1.txt b/Tests/Fixtures/application_run1.txt index 0b24a777c..2d6f6c666 100644 --- a/Tests/Fixtures/application_run1.txt +++ b/Tests/Fixtures/application_run1.txt @@ -5,7 +5,8 @@ Usage: Options: -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_run2.txt b/Tests/Fixtures/application_run2.txt index ccd73d14c..8523e16a6 100644 --- a/Tests/Fixtures/application_run2.txt +++ b/Tests/Fixtures/application_run2.txt @@ -12,7 +12,8 @@ Options: --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] --short To skip describing commands' arguments -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_run3.txt b/Tests/Fixtures/application_run3.txt index ccd73d14c..8523e16a6 100644 --- a/Tests/Fixtures/application_run3.txt +++ b/Tests/Fixtures/application_run3.txt @@ -12,7 +12,8 @@ Options: --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] --short To skip describing commands' arguments -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Fixtures/application_run5.txt b/Tests/Fixtures/application_run5.txt index de3fdd346..c5696492d 100644 --- a/Tests/Fixtures/application_run5.txt +++ b/Tests/Fixtures/application_run5.txt @@ -11,7 +11,8 @@ Options: --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] --raw To output raw command help -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question diff --git a/Tests/Output/NullOutputTest.php b/Tests/Output/NullOutputTest.php index 1e0967ea5..4da46cf8f 100644 --- a/Tests/Output/NullOutputTest.php +++ b/Tests/Output/NullOutputTest.php @@ -35,10 +35,10 @@ public function testConstructor() public function testVerbosity() { $output = new NullOutput(); - $this->assertSame(OutputInterface::VERBOSITY_QUIET, $output->getVerbosity(), '->getVerbosity() returns VERBOSITY_QUIET for NullOutput by default'); + $this->assertSame(OutputInterface::VERBOSITY_SILENT, $output->getVerbosity(), '->getVerbosity() returns VERBOSITY_SILENT for NullOutput by default'); $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); - $this->assertSame(OutputInterface::VERBOSITY_QUIET, $output->getVerbosity(), '->getVerbosity() always returns VERBOSITY_QUIET for NullOutput'); + $this->assertSame(OutputInterface::VERBOSITY_SILENT, $output->getVerbosity(), '->getVerbosity() always returns VERBOSITY_QUIET for NullOutput'); } public function testGetFormatter() @@ -60,7 +60,7 @@ public function testSetVerbosity() { $output = new NullOutput(); $output->setVerbosity(Output::VERBOSITY_NORMAL); - $this->assertEquals(Output::VERBOSITY_QUIET, $output->getVerbosity()); + $this->assertEquals(Output::VERBOSITY_SILENT, $output->getVerbosity()); } public function testSetDecorated() @@ -70,10 +70,16 @@ public function testSetDecorated() $this->assertFalse($output->isDecorated()); } + public function testIsSilent() + { + $output = new NullOutput(); + $this->assertTrue($output->isSilent()); + } + public function testIsQuiet() { $output = new NullOutput(); - $this->assertTrue($output->isQuiet()); + $this->assertFalse($output->isQuiet()); } public function testIsVerbose() diff --git a/Tests/Output/OutputTest.php b/Tests/Output/OutputTest.php index 8a1e2840e..64e491048 100644 --- a/Tests/Output/OutputTest.php +++ b/Tests/Output/OutputTest.php @@ -164,6 +164,7 @@ public function testWriteWithVerbosityOption($verbosity, $expected, $msg) public static function verbosityProvider() { return [ + [Output::VERBOSITY_SILENT, '', '->write() in SILENT mode never outputs'], [Output::VERBOSITY_QUIET, '2', '->write() in QUIET mode only outputs when an explicit QUIET verbosity is passed'], [Output::VERBOSITY_NORMAL, '123', '->write() in NORMAL mode outputs anything below an explicit VERBOSE verbosity'], [Output::VERBOSITY_VERBOSE, '1234', '->write() in VERBOSE mode outputs anything below an explicit VERY_VERBOSE verbosity'], diff --git a/Tests/phpt/single_application/help_name.phpt b/Tests/phpt/single_application/help_name.phpt index f3d220b72..3291c83c5 100644 --- a/Tests/phpt/single_application/help_name.phpt +++ b/Tests/phpt/single_application/help_name.phpt @@ -29,7 +29,8 @@ Usage: Options: -h, --help Display help for the given command. When no command is given display help for the %s command - -q, --quiet Do not output any message + --silent Do not output any message + -q, --quiet Only errors are displayed. All other output is suppressed -V, --version Display this application version --ansi|--no-ansi Force (or disable --no-ansi) ANSI output -n, --no-interaction Do not ask any interactive question From 300899a19db417c7be602aff998525e831545787 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 24 Sep 2024 12:58:43 +0200 Subject: [PATCH 42/59] Fix `$this` calls to static ones when relevant --- Command/DumpCompletionCommand.php | 2 +- EventListener/ErrorListener.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Command/DumpCompletionCommand.php b/Command/DumpCompletionCommand.php index daf3553ab..2853fc5f4 100644 --- a/Command/DumpCompletionCommand.php +++ b/Command/DumpCompletionCommand.php @@ -35,7 +35,7 @@ protected function configure(): void $commandName = basename($fullCommand); $fullCommand = @realpath($fullCommand) ?: $fullCommand; - $shell = $this->guessShell(); + $shell = self::guessShell(); [$rcFile, $completionFile] = match ($shell) { 'fish' => ['~/.config/fish/config.fish', "/etc/fish/completions/$commandName.fish"], 'zsh' => ['~/.zshrc', '$fpath[1]/_'.$commandName], diff --git a/EventListener/ErrorListener.php b/EventListener/ErrorListener.php index 87b0d70f1..9acb0e41d 100644 --- a/EventListener/ErrorListener.php +++ b/EventListener/ErrorListener.php @@ -37,7 +37,7 @@ public function onConsoleError(ConsoleErrorEvent $event): void $error = $event->getError(); - if (!$inputString = $this->getInputString($event)) { + if (!$inputString = self::getInputString($event)) { $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]); return; @@ -58,7 +58,7 @@ public function onConsoleTerminate(ConsoleTerminateEvent $event): void return; } - if (!$inputString = $this->getInputString($event)) { + if (!$inputString = self::getInputString($event)) { $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]); return; From dde368aa236153442f39a63c7ed27395ccd415c6 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 24 Sep 2024 13:28:07 +0200 Subject: [PATCH 43/59] Remove useless parent method calls in tests --- Tests/Question/QuestionTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/Question/QuestionTest.php b/Tests/Question/QuestionTest.php index 0bc6f75db..15d8212b9 100644 --- a/Tests/Question/QuestionTest.php +++ b/Tests/Question/QuestionTest.php @@ -20,7 +20,6 @@ class QuestionTest extends TestCase protected function setUp(): void { - parent::setUp(); $this->question = new Question('Test question'); } From dbccd36c99ceffc024f8ef557187b6f62b2058d2 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 26 Sep 2024 10:09:09 +0200 Subject: [PATCH 44/59] Remove unused imports --- Tests/Fixtures/Style/SymfonyStyle/command/command_19.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/Fixtures/Style/SymfonyStyle/command/command_19.php b/Tests/Fixtures/Style/SymfonyStyle/command/command_19.php index e44b18b76..e25a7ef29 100644 --- a/Tests/Fixtures/Style/SymfonyStyle/command/command_19.php +++ b/Tests/Fixtures/Style/SymfonyStyle/command/command_19.php @@ -1,6 +1,5 @@ Date: Tue, 1 Oct 2024 15:17:35 +0200 Subject: [PATCH 45/59] Remove a few unnecessary full qualifier --- Tests/Helper/TableCellStyleTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Helper/TableCellStyleTest.php b/Tests/Helper/TableCellStyleTest.php index ac80750eb..d934cf801 100644 --- a/Tests/Helper/TableCellStyleTest.php +++ b/Tests/Helper/TableCellStyleTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Tests\Helper; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Helper\TableCellStyle; class TableCellStyleTest extends TestCase @@ -21,7 +22,8 @@ public function testCreateTableCellStyle() $tableCellStyle = new TableCellStyle(['fg' => 'red']); $this->assertEquals('red', $tableCellStyle->getOptions()['fg']); - $this->expectException(\Symfony\Component\Console\Exception\InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); + new TableCellStyle(['wrong_key' => null]); } } From 6f86f8da2384dbf2a251fae8e8e615a7fec95756 Mon Sep 17 00:00:00 2001 From: Laurens Laman Date: Fri, 28 Jun 2024 11:27:52 +0200 Subject: [PATCH 46/59] Add finished indicator to ProgressIndicator --- CHANGELOG.md | 1 + Helper/ProgressIndicator.php | 22 +++++++++++++-- Tests/Helper/ProgressIndicatorTest.php | 37 ++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1581b5d4..a7b3c0450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG * Add `verbosity` argument to `mustRun` process helper method * [BC BREAK] Add silent verbosity (`--silent`/`SHELL_VERBOSITY=-2`) to suppress all output, including errors * Add `OutputInterface::isSilent()`, `Output::isSilent()`, `OutputStyle::isSilent()` methods + * Add a configurable finished indicator to the progress indicator to show that the progress is finished 7.1 --- diff --git a/Helper/ProgressIndicator.php b/Helper/ProgressIndicator.php index d06897d85..b6bbd0cfa 100644 --- a/Helper/ProgressIndicator.php +++ b/Helper/ProgressIndicator.php @@ -36,8 +36,10 @@ class ProgressIndicator private ?string $message = null; private array $indicatorValues; private int $indicatorCurrent; + private string $finishedIndicatorValue; private float $indicatorUpdateTime; private bool $started = false; + private bool $finished = false; /** * @var array @@ -53,10 +55,12 @@ public function __construct( ?string $format = null, private int $indicatorChangeInterval = 100, ?array $indicatorValues = null, + ?string $finishedIndicatorValue = null, ) { $format ??= $this->determineBestFormat(); $indicatorValues ??= ['-', '\\', '|', '/']; $indicatorValues = array_values($indicatorValues); + $finishedIndicatorValue ??= '✔'; if (2 > \count($indicatorValues)) { throw new InvalidArgumentException('Must have at least 2 indicator value characters.'); @@ -64,6 +68,7 @@ public function __construct( $this->format = self::getFormatDefinition($format); $this->indicatorValues = $indicatorValues; + $this->finishedIndicatorValue = $finishedIndicatorValue; $this->startTime = time(); } @@ -88,6 +93,7 @@ public function start(string $message): void $this->message = $message; $this->started = true; + $this->finished = false; $this->startTime = time(); $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; $this->indicatorCurrent = 0; @@ -122,13 +128,25 @@ public function advance(): void /** * Finish the indicator with message. + * + * @param ?string $finishedIndicator */ - public function finish(string $message): void + public function finish(string $message/* , ?string $finishedIndicator = null */): void { + $finishedIndicator = 1 < \func_num_args() ? func_get_arg(1) : null; + if (null !== $finishedIndicator && !\is_string($finishedIndicator)) { + throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be of the type string or null, "%s" given.', __METHOD__, get_debug_type($finishedIndicator))); + } + if (!$this->started) { throw new LogicException('Progress indicator has not yet been started.'); } + if (null !== $finishedIndicator) { + $this->finishedIndicatorValue = $finishedIndicator; + } + + $this->finished = true; $this->message = $message; $this->display(); $this->output->writeln(''); @@ -215,7 +233,7 @@ private function getCurrentTimeInMilliseconds(): float private static function initPlaceholderFormatters(): array { return [ - 'indicator' => fn (self $indicator) => $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], + 'indicator' => fn (self $indicator) => $indicator->finished ? $indicator->finishedIndicatorValue : $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)], 'message' => fn (self $indicator) => $indicator->message, 'elapsed' => fn (self $indicator) => Helper::formatTime(time() - $indicator->startTime, 2), 'memory' => fn () => Helper::formatMemory(memory_get_usage(true)), diff --git a/Tests/Helper/ProgressIndicatorTest.php b/Tests/Helper/ProgressIndicatorTest.php index 8e2e10e37..2a4441d57 100644 --- a/Tests/Helper/ProgressIndicatorTest.php +++ b/Tests/Helper/ProgressIndicatorTest.php @@ -54,11 +54,11 @@ public function testDefaultIndicator() $this->generateOutput(' \\ Starting...'). $this->generateOutput(' \\ Advancing...'). $this->generateOutput(' | Advancing...'). - $this->generateOutput(' | Done...'). + $this->generateOutput(' ✔ Done...'). \PHP_EOL. $this->generateOutput(' - Starting Again...'). $this->generateOutput(' \\ Starting Again...'). - $this->generateOutput(' \\ Done Again...'). + $this->generateOutput(' ✔ Done Again...'). \PHP_EOL, stream_get_contents($output->getStream()) ); @@ -109,6 +109,39 @@ public function testCustomIndicatorValues() ); } + public function testCustomFinishedIndicatorValue() + { + $bar = new ProgressIndicator($output = $this->getOutputStream(), null, 100, ['a', 'b'], '✅'); + + $bar->start('Starting...'); + usleep(101000); + $bar->finish('Done'); + + rewind($output->getStream()); + + $this->assertSame( + $this->generateOutput(' a Starting...'). + $this->generateOutput(' ✅ Done').\PHP_EOL, + stream_get_contents($output->getStream()) + ); + } + + public function testCustomFinishedIndicatorWhenFinishingProcess() + { + $bar = new ProgressIndicator($output = $this->getOutputStream(), null, 100, ['a', 'b']); + + $bar->start('Starting...'); + $bar->finish('Process failed', '❌'); + + rewind($output->getStream()); + + $this->assertEquals( + $this->generateOutput(' a Starting...'). + $this->generateOutput(' ❌ Process failed').\PHP_EOL, + stream_get_contents($output->getStream()) + ); + } + public function testCannotSetInvalidIndicatorCharacters() { $this->expectException(\InvalidArgumentException::class); From 84539561c69f597508b990af8a552b7c05b6257e Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 3 Oct 2024 14:15:19 +0200 Subject: [PATCH 47/59] Various CS fix for consistency --- Tests/Fixtures/application_signalable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Fixtures/application_signalable.php b/Tests/Fixtures/application_signalable.php index 12cf744ea..978406637 100644 --- a/Tests/Fixtures/application_signalable.php +++ b/Tests/Fixtures/application_signalable.php @@ -12,7 +12,7 @@ } require $vendor.'/vendor/autoload.php'; -(new class() extends SingleCommandApplication implements SignalableCommandInterface { +(new class extends SingleCommandApplication implements SignalableCommandInterface { public function getSubscribedSignals(): array { return [SIGINT]; From 270fd988c707d8d3aeae056de564130d3cd1b2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Fri, 4 Oct 2024 11:00:10 +0200 Subject: [PATCH 48/59] [Console] Use assertSame for input tests --- Tests/Input/ArgvInputTest.php | 50 ++++++++++++------------- Tests/Input/ArrayInputTest.php | 20 +++++----- Tests/Input/InputArgumentTest.php | 10 ++--- Tests/Input/InputDefinitionTest.php | 58 ++++++++++++++--------------- Tests/Input/InputOptionTest.php | 32 ++++++++-------- Tests/Input/InputTest.php | 28 +++++++------- Tests/Input/StringInputTest.php | 10 ++--- 7 files changed, 104 insertions(+), 104 deletions(-) diff --git a/Tests/Input/ArgvInputTest.php b/Tests/Input/ArgvInputTest.php index 31b4b03dd..0e76f9ee6 100644 --- a/Tests/Input/ArgvInputTest.php +++ b/Tests/Input/ArgvInputTest.php @@ -26,17 +26,17 @@ public function testConstructor() $r = new \ReflectionObject($input); $p = $r->getProperty('tokens'); - $this->assertEquals(['foo'], $p->getValue($input), '__construct() automatically get its input from the argv server variable'); + $this->assertSame(['foo'], $p->getValue($input), '__construct() automatically get its input from the argv server variable'); } public function testParseArguments() { $input = new ArgvInput(['cli.php', 'foo']); $input->bind(new InputDefinition([new InputArgument('name')])); - $this->assertEquals(['name' => 'foo'], $input->getArguments(), '->parse() parses required arguments'); + $this->assertSame(['name' => 'foo'], $input->getArguments(), '->parse() parses required arguments'); $input->bind(new InputDefinition([new InputArgument('name')])); - $this->assertEquals(['name' => 'foo'], $input->getArguments(), '->parse() is stateless'); + $this->assertSame(['name' => 'foo'], $input->getArguments(), '->parse() is stateless'); } /** @@ -57,7 +57,7 @@ public function testParseOptionsNegatable($input, $options, $expectedOptions, $m { $input = new ArgvInput($input); $input->bind(new InputDefinition($options)); - $this->assertEquals($expectedOptions, $input->getOptions(), $message); + $this->assertSame($expectedOptions, $input->getOptions(), $message); } public static function provideOptions() @@ -363,7 +363,7 @@ public function testParseArrayArgument() $input = new ArgvInput(['cli.php', 'foo', 'bar', 'baz', 'bat']); $input->bind(new InputDefinition([new InputArgument('name', InputArgument::IS_ARRAY)])); - $this->assertEquals(['name' => ['foo', 'bar', 'baz', 'bat']], $input->getArguments(), '->parse() parses array arguments'); + $this->assertSame(['name' => ['foo', 'bar', 'baz', 'bat']], $input->getArguments(), '->parse() parses array arguments'); } public function testParseArrayOption() @@ -371,11 +371,11 @@ public function testParseArrayOption() $input = new ArgvInput(['cli.php', '--name=foo', '--name=bar', '--name=baz']); $input->bind(new InputDefinition([new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)])); - $this->assertEquals(['name' => ['foo', 'bar', 'baz']], $input->getOptions(), '->parse() parses array options ("--option=value" syntax)'); + $this->assertSame(['name' => ['foo', 'bar', 'baz']], $input->getOptions(), '->parse() parses array options ("--option=value" syntax)'); $input = new ArgvInput(['cli.php', '--name', 'foo', '--name', 'bar', '--name', 'baz']); $input->bind(new InputDefinition([new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)])); - $this->assertEquals(['name' => ['foo', 'bar', 'baz']], $input->getOptions(), '->parse() parses array options ("--option value" syntax)'); + $this->assertSame(['name' => ['foo', 'bar', 'baz']], $input->getOptions(), '->parse() parses array options ("--option value" syntax)'); $input = new ArgvInput(['cli.php', '--name=foo', '--name=bar', '--name=']); $input->bind(new InputDefinition([new InputOption('name', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY)])); @@ -393,12 +393,12 @@ public function testParseNegativeNumberAfterDoubleDash() { $input = new ArgvInput(['cli.php', '--', '-1']); $input->bind(new InputDefinition([new InputArgument('number')])); - $this->assertEquals(['number' => '-1'], $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); + $this->assertSame(['number' => '-1'], $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); $input = new ArgvInput(['cli.php', '-f', 'bar', '--', '-1']); $input->bind(new InputDefinition([new InputArgument('number'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)])); - $this->assertEquals(['foo' => 'bar'], $input->getOptions(), '->parse() parses arguments with leading dashes as options before having encountered a double-dash sequence'); - $this->assertEquals(['number' => '-1'], $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); + $this->assertSame(['foo' => 'bar'], $input->getOptions(), '->parse() parses arguments with leading dashes as options before having encountered a double-dash sequence'); + $this->assertSame(['number' => '-1'], $input->getArguments(), '->parse() parses arguments with leading dashes as arguments after having encountered a double-dash sequence'); } public function testParseEmptyStringArgument() @@ -406,7 +406,7 @@ public function testParseEmptyStringArgument() $input = new ArgvInput(['cli.php', '-f', 'bar', '']); $input->bind(new InputDefinition([new InputArgument('empty'), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)])); - $this->assertEquals(['empty' => ''], $input->getArguments(), '->parse() parses empty string arguments'); + $this->assertSame(['empty' => ''], $input->getArguments(), '->parse() parses empty string arguments'); } public function testGetFirstArgument() @@ -415,7 +415,7 @@ public function testGetFirstArgument() $this->assertNull($input->getFirstArgument(), '->getFirstArgument() returns null when there is no arguments'); $input = new ArgvInput(['cli.php', '-fbbar', 'foo']); - $this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); + $this->assertSame('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); $input = new ArgvInput(['cli.php', '--foo', 'fooval', 'bar']); $input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')])); @@ -495,7 +495,7 @@ public function testNoWarningOnInvalidParameterOption() // No warning thrown $this->assertFalse($input->hasParameterOption(['-m', ''])); - $this->assertEquals('dev', $input->getParameterOption(['-e', ''])); + $this->assertSame('dev', $input->getParameterOption(['-e', ''])); // No warning thrown $this->assertFalse($input->getParameterOption(['-m', ''])); } @@ -503,10 +503,10 @@ public function testNoWarningOnInvalidParameterOption() public function testToString() { $input = new ArgvInput(['cli.php', '-f', 'foo']); - $this->assertEquals('-f foo', (string) $input); + $this->assertSame('-f foo', (string) $input); $input = new ArgvInput(['cli.php', '-f', '--bar=foo', 'a b c d', "A\nB'C"]); - $this->assertEquals('-f --bar=foo '.escapeshellarg('a b c d').' '.escapeshellarg("A\nB'C"), (string) $input); + $this->assertSame('-f --bar=foo '.escapeshellarg('a b c d').' '.escapeshellarg("A\nB'C"), (string) $input); } /** @@ -515,7 +515,7 @@ public function testToString() public function testGetParameterOptionEqualSign($argv, $key, $default, $onlyParams, $expected) { $input = new ArgvInput($argv); - $this->assertEquals($expected, $input->getParameterOption($key, $default, $onlyParams), '->getParameterOption() returns the expected value'); + $this->assertSame($expected, $input->getParameterOption($key, $default, $onlyParams), '->getParameterOption() returns the expected value'); } public static function provideGetParameterOptionValues() @@ -539,33 +539,33 @@ public function testParseSingleDashAsArgument() { $input = new ArgvInput(['cli.php', '-']); $input->bind(new InputDefinition([new InputArgument('file')])); - $this->assertEquals(['file' => '-'], $input->getArguments(), '->parse() parses single dash as an argument'); + $this->assertSame(['file' => '-'], $input->getArguments(), '->parse() parses single dash as an argument'); } public function testParseOptionWithValueOptionalGivenEmptyAndRequiredArgument() { $input = new ArgvInput(['cli.php', '--foo=', 'bar']); $input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::REQUIRED)])); - $this->assertEquals(['foo' => null], $input->getOptions(), '->parse() parses optional options with empty value as null'); - $this->assertEquals(['name' => 'bar'], $input->getArguments(), '->parse() parses required arguments'); + $this->assertSame(['foo' => ''], $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertSame(['name' => 'bar'], $input->getArguments(), '->parse() parses required arguments'); $input = new ArgvInput(['cli.php', '--foo=0', 'bar']); $input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::REQUIRED)])); - $this->assertEquals(['foo' => '0'], $input->getOptions(), '->parse() parses optional options with empty value as null'); - $this->assertEquals(['name' => 'bar'], $input->getArguments(), '->parse() parses required arguments'); + $this->assertSame(['foo' => '0'], $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertSame(['name' => 'bar'], $input->getArguments(), '->parse() parses required arguments'); } public function testParseOptionWithValueOptionalGivenEmptyAndOptionalArgument() { $input = new ArgvInput(['cli.php', '--foo=', 'bar']); $input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::OPTIONAL)])); - $this->assertEquals(['foo' => null], $input->getOptions(), '->parse() parses optional options with empty value as null'); - $this->assertEquals(['name' => 'bar'], $input->getArguments(), '->parse() parses optional arguments'); + $this->assertSame(['foo' => ''], $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertSame(['name' => 'bar'], $input->getArguments(), '->parse() parses optional arguments'); $input = new ArgvInput(['cli.php', '--foo=0', 'bar']); $input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('name', InputArgument::OPTIONAL)])); - $this->assertEquals(['foo' => '0'], $input->getOptions(), '->parse() parses optional options with empty value as null'); - $this->assertEquals(['name' => 'bar'], $input->getArguments(), '->parse() parses optional arguments'); + $this->assertSame(['foo' => '0'], $input->getOptions(), '->parse() parses optional options with empty value as null'); + $this->assertSame(['name' => 'bar'], $input->getArguments(), '->parse() parses optional arguments'); } public function testGetRawTokensFalse() diff --git a/Tests/Input/ArrayInputTest.php b/Tests/Input/ArrayInputTest.php index d6fe32bb3..74d2c089f 100644 --- a/Tests/Input/ArrayInputTest.php +++ b/Tests/Input/ArrayInputTest.php @@ -24,9 +24,9 @@ public function testGetFirstArgument() $input = new ArrayInput([]); $this->assertNull($input->getFirstArgument(), '->getFirstArgument() returns null if no argument were passed'); $input = new ArrayInput(['name' => 'Fabien']); - $this->assertEquals('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); + $this->assertSame('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); $input = new ArrayInput(['--foo' => 'bar', 'name' => 'Fabien']); - $this->assertEquals('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); + $this->assertSame('Fabien', $input->getFirstArgument(), '->getFirstArgument() returns the first passed argument'); } public function testHasParameterOption() @@ -46,22 +46,22 @@ public function testHasParameterOption() public function testGetParameterOption() { $input = new ArrayInput(['name' => 'Fabien', '--foo' => 'bar']); - $this->assertEquals('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name'); - $this->assertEquals('default', $input->getParameterOption('--bar', 'default'), '->getParameterOption() returns the default value if an option is not present in the passed parameters'); + $this->assertSame('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name'); + $this->assertSame('default', $input->getParameterOption('--bar', 'default'), '->getParameterOption() returns the default value if an option is not present in the passed parameters'); $input = new ArrayInput(['Fabien', '--foo' => 'bar']); - $this->assertEquals('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name'); + $this->assertSame('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name'); $input = new ArrayInput(['--foo', '--', '--bar' => 'woop']); - $this->assertEquals('woop', $input->getParameterOption('--bar'), '->getParameterOption() returns the correct value if an option is present in the passed parameters'); - $this->assertEquals('default', $input->getParameterOption('--bar', 'default', true), '->getParameterOption() returns the default value if an option is present in the passed parameters after an end of options signal'); + $this->assertSame('woop', $input->getParameterOption('--bar'), '->getParameterOption() returns the correct value if an option is present in the passed parameters'); + $this->assertSame('default', $input->getParameterOption('--bar', 'default', true), '->getParameterOption() returns the default value if an option is present in the passed parameters after an end of options signal'); } public function testParseArguments() { $input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name')])); - $this->assertEquals(['name' => 'foo'], $input->getArguments(), '->parse() parses required arguments'); + $this->assertSame(['name' => 'foo'], $input->getArguments(), '->parse() parses required arguments'); } /** @@ -71,7 +71,7 @@ public function testParseOptions($input, $options, $expectedOptions, $message) { $input = new ArrayInput($input, new InputDefinition($options)); - $this->assertEquals($expectedOptions, $input->getOptions(), $message); + $this->assertSame($expectedOptions, $input->getOptions(), $message); } public static function provideOptions(): array @@ -162,7 +162,7 @@ public static function provideInvalidInput(): array public function testToString() { $input = new ArrayInput(['-f' => null, '-b' => 'bar', '--foo' => 'b a z', '--lala' => null, 'test' => 'Foo', 'test2' => "A\nB'C"]); - $this->assertEquals('-f -b bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input); + $this->assertSame('-f -b bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input); $input = new ArrayInput(['-b' => ['bval_1', 'bval_2'], '--f' => ['fval_1', 'fval_2']]); $this->assertSame('-b bval_1 -b bval_2 --f=fval_1 --f=fval_2', (string) $input); diff --git a/Tests/Input/InputArgumentTest.php b/Tests/Input/InputArgumentTest.php index 05447426c..a9d612f97 100644 --- a/Tests/Input/InputArgumentTest.php +++ b/Tests/Input/InputArgumentTest.php @@ -23,7 +23,7 @@ class InputArgumentTest extends TestCase public function testConstructor() { $argument = new InputArgument('foo'); - $this->assertEquals('foo', $argument->getName(), '__construct() takes a name as its first argument'); + $this->assertSame('foo', $argument->getName(), '__construct() takes a name as its first argument'); } public function testModes() @@ -62,13 +62,13 @@ public function testIsArray() public function testGetDescription() { $argument = new InputArgument('foo', null, 'Some description'); - $this->assertEquals('Some description', $argument->getDescription(), '->getDescription() return the message description'); + $this->assertSame('Some description', $argument->getDescription(), '->getDescription() return the message description'); } public function testGetDefault() { $argument = new InputArgument('foo', InputArgument::OPTIONAL, '', 'default'); - $this->assertEquals('default', $argument->getDefault(), '->getDefault() return the default value'); + $this->assertSame('default', $argument->getDefault(), '->getDefault() return the default value'); } public function testSetDefault() @@ -77,11 +77,11 @@ public function testSetDefault() $argument->setDefault(null); $this->assertNull($argument->getDefault(), '->setDefault() can reset the default value by passing null'); $argument->setDefault('another'); - $this->assertEquals('another', $argument->getDefault(), '->setDefault() changes the default value'); + $this->assertSame('another', $argument->getDefault(), '->setDefault() changes the default value'); $argument = new InputArgument('foo', InputArgument::OPTIONAL | InputArgument::IS_ARRAY); $argument->setDefault([1, 2]); - $this->assertEquals([1, 2], $argument->getDefault(), '->setDefault() changes the default value'); + $this->assertSame([1, 2], $argument->getDefault(), '->setDefault() changes the default value'); } public function testSetDefaultWithRequiredArgument() diff --git a/Tests/Input/InputDefinitionTest.php b/Tests/Input/InputDefinitionTest.php index a3fd3e2ea..ab203e6e5 100644 --- a/Tests/Input/InputDefinitionTest.php +++ b/Tests/Input/InputDefinitionTest.php @@ -36,10 +36,10 @@ public function testConstructorArguments() $this->initializeArguments(); $definition = new InputDefinition(); - $this->assertEquals([], $definition->getArguments(), '__construct() creates a new InputDefinition object'); + $this->assertSame([], $definition->getArguments(), '__construct() creates a new InputDefinition object'); $definition = new InputDefinition([$this->foo, $this->bar]); - $this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '__construct() takes an array of InputArgument objects as its first argument'); + $this->assertSame(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '__construct() takes an array of InputArgument objects as its first argument'); } public function testConstructorOptions() @@ -47,10 +47,10 @@ public function testConstructorOptions() $this->initializeOptions(); $definition = new InputDefinition(); - $this->assertEquals([], $definition->getOptions(), '__construct() creates a new InputDefinition object'); + $this->assertSame([], $definition->getOptions(), '__construct() creates a new InputDefinition object'); $definition = new InputDefinition([$this->foo, $this->bar]); - $this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '__construct() takes an array of InputOption objects as its first argument'); + $this->assertSame(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '__construct() takes an array of InputOption objects as its first argument'); } public function testSetArguments() @@ -59,10 +59,10 @@ public function testSetArguments() $definition = new InputDefinition(); $definition->setArguments([$this->foo]); - $this->assertEquals(['foo' => $this->foo], $definition->getArguments(), '->setArguments() sets the array of InputArgument objects'); + $this->assertSame(['foo' => $this->foo], $definition->getArguments(), '->setArguments() sets the array of InputArgument objects'); $definition->setArguments([$this->bar]); - $this->assertEquals(['bar' => $this->bar], $definition->getArguments(), '->setArguments() clears all InputArgument objects'); + $this->assertSame(['bar' => $this->bar], $definition->getArguments(), '->setArguments() clears all InputArgument objects'); } public function testAddArguments() @@ -71,9 +71,9 @@ public function testAddArguments() $definition = new InputDefinition(); $definition->addArguments([$this->foo]); - $this->assertEquals(['foo' => $this->foo], $definition->getArguments(), '->addArguments() adds an array of InputArgument objects'); + $this->assertSame(['foo' => $this->foo], $definition->getArguments(), '->addArguments() adds an array of InputArgument objects'); $definition->addArguments([$this->bar]); - $this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '->addArguments() does not clear existing InputArgument objects'); + $this->assertSame(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '->addArguments() does not clear existing InputArgument objects'); } public function testAddArgument() @@ -82,9 +82,9 @@ public function testAddArgument() $definition = new InputDefinition(); $definition->addArgument($this->foo); - $this->assertEquals(['foo' => $this->foo], $definition->getArguments(), '->addArgument() adds a InputArgument object'); + $this->assertSame(['foo' => $this->foo], $definition->getArguments(), '->addArgument() adds a InputArgument object'); $definition->addArgument($this->bar); - $this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '->addArgument() adds a InputArgument object'); + $this->assertSame(['foo' => $this->foo, 'bar' => $this->bar], $definition->getArguments(), '->addArgument() adds a InputArgument object'); } public function testArgumentsMustHaveDifferentNames() @@ -126,7 +126,7 @@ public function testGetArgument() $definition = new InputDefinition(); $definition->addArguments([$this->foo]); - $this->assertEquals($this->foo, $definition->getArgument('foo'), '->getArgument() returns a InputArgument by its name'); + $this->assertSame($this->foo, $definition->getArgument('foo'), '->getArgument() returns a InputArgument by its name'); } public function testGetInvalidArgument() @@ -157,9 +157,9 @@ public function testGetArgumentRequiredCount() $definition = new InputDefinition(); $definition->addArgument($this->foo2); - $this->assertEquals(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); + $this->assertSame(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); $definition->addArgument($this->foo); - $this->assertEquals(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); + $this->assertSame(1, $definition->getArgumentRequiredCount(), '->getArgumentRequiredCount() returns the number of required arguments'); } public function testGetArgumentCount() @@ -168,9 +168,9 @@ public function testGetArgumentCount() $definition = new InputDefinition(); $definition->addArgument($this->foo2); - $this->assertEquals(1, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); + $this->assertSame(1, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); $definition->addArgument($this->foo); - $this->assertEquals(2, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); + $this->assertSame(2, $definition->getArgumentCount(), '->getArgumentCount() returns the number of arguments'); } public function testGetArgumentDefaults() @@ -181,12 +181,12 @@ public function testGetArgumentDefaults() new InputArgument('foo3', InputArgument::OPTIONAL | InputArgument::IS_ARRAY), // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', [1, 2]), ]); - $this->assertEquals(['foo1' => null, 'foo2' => 'default', 'foo3' => []], $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); + $this->assertSame(['foo1' => null, 'foo2' => 'default', 'foo3' => []], $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); $definition = new InputDefinition([ new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', [1, 2]), ]); - $this->assertEquals(['foo4' => [1, 2]], $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); + $this->assertSame(['foo4' => [1, 2]], $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); } public function testSetOptions() @@ -194,9 +194,9 @@ public function testSetOptions() $this->initializeOptions(); $definition = new InputDefinition([$this->foo]); - $this->assertEquals(['foo' => $this->foo], $definition->getOptions(), '->setOptions() sets the array of InputOption objects'); + $this->assertSame(['foo' => $this->foo], $definition->getOptions(), '->setOptions() sets the array of InputOption objects'); $definition->setOptions([$this->bar]); - $this->assertEquals(['bar' => $this->bar], $definition->getOptions(), '->setOptions() clears all InputOption objects'); + $this->assertSame(['bar' => $this->bar], $definition->getOptions(), '->setOptions() clears all InputOption objects'); } public function testSetOptionsClearsOptions() @@ -215,9 +215,9 @@ public function testAddOptions() $this->initializeOptions(); $definition = new InputDefinition([$this->foo]); - $this->assertEquals(['foo' => $this->foo], $definition->getOptions(), '->addOptions() adds an array of InputOption objects'); + $this->assertSame(['foo' => $this->foo], $definition->getOptions(), '->addOptions() adds an array of InputOption objects'); $definition->addOptions([$this->bar]); - $this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '->addOptions() does not clear existing InputOption objects'); + $this->assertSame(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '->addOptions() does not clear existing InputOption objects'); } public function testAddOption() @@ -226,9 +226,9 @@ public function testAddOption() $definition = new InputDefinition(); $definition->addOption($this->foo); - $this->assertEquals(['foo' => $this->foo], $definition->getOptions(), '->addOption() adds a InputOption object'); + $this->assertSame(['foo' => $this->foo], $definition->getOptions(), '->addOption() adds a InputOption object'); $definition->addOption($this->bar); - $this->assertEquals(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '->addOption() adds a InputOption object'); + $this->assertSame(['foo' => $this->foo, 'bar' => $this->bar], $definition->getOptions(), '->addOption() adds a InputOption object'); } public function testAddDuplicateOption() @@ -278,7 +278,7 @@ public function testGetOption() $this->initializeOptions(); $definition = new InputDefinition([$this->foo]); - $this->assertEquals($this->foo, $definition->getOption('foo'), '->getOption() returns a InputOption by its name'); + $this->assertSame($this->foo, $definition->getOption('foo'), '->getOption() returns a InputOption by its name'); } public function testGetInvalidOption() @@ -314,7 +314,7 @@ public function testGetOptionForShortcut() $this->initializeOptions(); $definition = new InputDefinition([$this->foo]); - $this->assertEquals($this->foo, $definition->getOptionForShortcut('f'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + $this->assertSame($this->foo, $definition->getOptionForShortcut('f'), '->getOptionForShortcut() returns a InputOption by its shortcut'); } public function testGetOptionForMultiShortcut() @@ -322,8 +322,8 @@ public function testGetOptionForMultiShortcut() $this->initializeOptions(); $definition = new InputDefinition([$this->multi]); - $this->assertEquals($this->multi, $definition->getOptionForShortcut('m'), '->getOptionForShortcut() returns a InputOption by its shortcut'); - $this->assertEquals($this->multi, $definition->getOptionForShortcut('mmm'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + $this->assertSame($this->multi, $definition->getOptionForShortcut('m'), '->getOptionForShortcut() returns a InputOption by its shortcut'); + $this->assertSame($this->multi, $definition->getOptionForShortcut('mmm'), '->getOptionForShortcut() returns a InputOption by its shortcut'); } public function testGetOptionForInvalidShortcut() @@ -364,7 +364,7 @@ public function testGetOptionDefaults() */ public function testGetSynopsis(InputDefinition $definition, $expectedSynopsis, $message = null) { - $this->assertEquals($expectedSynopsis, $definition->getSynopsis(), $message ? '->getSynopsis() '.$message : ''); + $this->assertSame($expectedSynopsis, $definition->getSynopsis(), $message ? '->getSynopsis() '.$message : ''); } public static function getGetSynopsisData() @@ -388,7 +388,7 @@ public static function getGetSynopsisData() public function testGetShortSynopsis() { $definition = new InputDefinition([new InputOption('foo'), new InputOption('bar'), new InputArgument('cat')]); - $this->assertEquals('[options] [--] []', $definition->getSynopsis(true), '->getSynopsis(true) groups options in [options]'); + $this->assertSame('[options] [--] []', $definition->getSynopsis(true), '->getSynopsis(true) groups options in [options]'); } protected function initializeArguments() diff --git a/Tests/Input/InputOptionTest.php b/Tests/Input/InputOptionTest.php index 7e3fb16da..47ab503f7 100644 --- a/Tests/Input/InputOptionTest.php +++ b/Tests/Input/InputOptionTest.php @@ -23,9 +23,9 @@ class InputOptionTest extends TestCase public function testConstructor() { $option = new InputOption('foo'); - $this->assertEquals('foo', $option->getName(), '__construct() takes a name as its first argument'); + $this->assertSame('foo', $option->getName(), '__construct() takes a name as its first argument'); $option = new InputOption('--foo'); - $this->assertEquals('foo', $option->getName(), '__construct() removes the leading -- of the option name'); + $this->assertSame('foo', $option->getName(), '__construct() removes the leading -- of the option name'); } public function testArrayModeWithoutValue() @@ -52,11 +52,11 @@ public function testBooleanWithOptional() public function testShortcut() { $option = new InputOption('foo', 'f'); - $this->assertEquals('f', $option->getShortcut(), '__construct() can take a shortcut as its second argument'); + $this->assertSame('f', $option->getShortcut(), '__construct() can take a shortcut as its second argument'); $option = new InputOption('foo', '-f|-ff|fff'); - $this->assertEquals('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts'); + $this->assertSame('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts'); $option = new InputOption('foo', ['f', 'ff', '-fff']); - $this->assertEquals('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts'); + $this->assertSame('f|ff|fff', $option->getShortcut(), '__construct() removes the leading - of the shortcuts'); $option = new InputOption('foo'); $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null by default'); $option = new InputOption('foo', ''); @@ -64,15 +64,15 @@ public function testShortcut() $option = new InputOption('foo', []); $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given an empty array'); $option = new InputOption('foo', ['f', '', 'fff']); - $this->assertEquals('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts'); + $this->assertSame('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts'); $option = new InputOption('foo', 'f||fff'); - $this->assertEquals('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts'); + $this->assertSame('f|fff', $option->getShortcut(), '__construct() removes empty shortcuts'); $option = new InputOption('foo', '0'); - $this->assertEquals('0', $option->getShortcut(), '-0 is an acceptable shortcut value'); + $this->assertSame('0', $option->getShortcut(), '-0 is an acceptable shortcut value'); $option = new InputOption('foo', ['0', 'z']); - $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in an array'); + $this->assertSame('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in an array'); $option = new InputOption('foo', '0|z'); - $this->assertEquals('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in a string-list'); + $this->assertSame('0|z', $option->getShortcut(), '-0 is an acceptable shortcut value when embedded in a string-list'); $option = new InputOption('foo', false); $this->assertNull($option->getShortcut(), '__construct() makes the shortcut null when given a false as value'); } @@ -142,22 +142,22 @@ public function testIsArray() public function testGetDescription() { $option = new InputOption('foo', 'f', null, 'Some description'); - $this->assertEquals('Some description', $option->getDescription(), '->getDescription() returns the description message'); + $this->assertSame('Some description', $option->getDescription(), '->getDescription() returns the description message'); } public function testGetDefault() { $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL, '', 'default'); - $this->assertEquals('default', $option->getDefault(), '->getDefault() returns the default value'); + $this->assertSame('default', $option->getDefault(), '->getDefault() returns the default value'); $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED, '', 'default'); - $this->assertEquals('default', $option->getDefault(), '->getDefault() returns the default value'); + $this->assertSame('default', $option->getDefault(), '->getDefault() returns the default value'); $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED); $this->assertNull($option->getDefault(), '->getDefault() returns null if no default value is configured'); $option = new InputOption('foo', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY); - $this->assertEquals([], $option->getDefault(), '->getDefault() returns an empty array if option is an array'); + $this->assertSame([], $option->getDefault(), '->getDefault() returns an empty array if option is an array'); $option = new InputOption('foo', null, InputOption::VALUE_NONE); $this->assertFalse($option->getDefault(), '->getDefault() returns false if the option does not take a value'); @@ -169,11 +169,11 @@ public function testSetDefault() $option->setDefault(null); $this->assertNull($option->getDefault(), '->setDefault() can reset the default value by passing null'); $option->setDefault('another'); - $this->assertEquals('another', $option->getDefault(), '->setDefault() changes the default value'); + $this->assertSame('another', $option->getDefault(), '->setDefault() changes the default value'); $option = new InputOption('foo', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY); $option->setDefault([1, 2]); - $this->assertEquals([1, 2], $option->getDefault(), '->setDefault() changes the default value'); + $this->assertSame([1, 2], $option->getDefault(), '->setDefault() changes the default value'); } public function testDefaultValueWithValueNoneMode() diff --git a/Tests/Input/InputTest.php b/Tests/Input/InputTest.php index 34fb4833b..19a840da6 100644 --- a/Tests/Input/InputTest.php +++ b/Tests/Input/InputTest.php @@ -22,29 +22,29 @@ class InputTest extends TestCase public function testConstructor() { $input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name')])); - $this->assertEquals('foo', $input->getArgument('name'), '->__construct() takes a InputDefinition as an argument'); + $this->assertSame('foo', $input->getArgument('name'), '->__construct() takes a InputDefinition as an argument'); } public function testOptions() { $input = new ArrayInput(['--name' => 'foo'], new InputDefinition([new InputOption('name')])); - $this->assertEquals('foo', $input->getOption('name'), '->getOption() returns the value for the given option'); + $this->assertSame('foo', $input->getOption('name'), '->getOption() returns the value for the given option'); $input->setOption('name', 'bar'); - $this->assertEquals('bar', $input->getOption('name'), '->setOption() sets the value for a given option'); - $this->assertEquals(['name' => 'bar'], $input->getOptions(), '->getOptions() returns all option values'); + $this->assertSame('bar', $input->getOption('name'), '->setOption() sets the value for a given option'); + $this->assertSame(['name' => 'bar'], $input->getOptions(), '->getOptions() returns all option values'); $input = new ArrayInput(['--name' => 'foo'], new InputDefinition([new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')])); - $this->assertEquals('default', $input->getOption('bar'), '->getOption() returns the default value for optional options'); - $this->assertEquals(['name' => 'foo', 'bar' => 'default'], $input->getOptions(), '->getOptions() returns all option values, even optional ones'); + $this->assertSame('default', $input->getOption('bar'), '->getOption() returns the default value for optional options'); + $this->assertSame(['name' => 'foo', 'bar' => 'default'], $input->getOptions(), '->getOptions() returns all option values, even optional ones'); $input = new ArrayInput(['--name' => 'foo', '--bar' => ''], new InputDefinition([new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')])); - $this->assertEquals('', $input->getOption('bar'), '->getOption() returns null for options explicitly passed without value (or an empty value)'); - $this->assertEquals(['name' => 'foo', 'bar' => ''], $input->getOptions(), '->getOptions() returns all option values.'); + $this->assertSame('', $input->getOption('bar'), '->getOption() returns null for options explicitly passed without value (or an empty value)'); + $this->assertSame(['name' => 'foo', 'bar' => ''], $input->getOptions(), '->getOptions() returns all option values.'); $input = new ArrayInput(['--name' => 'foo', '--bar' => null], new InputDefinition([new InputOption('name'), new InputOption('bar', '', InputOption::VALUE_OPTIONAL, '', 'default')])); $this->assertNull($input->getOption('bar'), '->getOption() returns null for options explicitly passed without value (or an empty value)'); - $this->assertEquals(['name' => 'foo', 'bar' => null], $input->getOptions(), '->getOptions() returns all option values'); + $this->assertSame(['name' => 'foo', 'bar' => null], $input->getOptions(), '->getOptions() returns all option values'); $input = new ArrayInput(['--name' => null], new InputDefinition([new InputOption('name', null, InputOption::VALUE_NEGATABLE)])); $this->assertTrue($input->hasOption('name')); @@ -84,15 +84,15 @@ public function testGetInvalidOption() public function testArguments() { $input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name')])); - $this->assertEquals('foo', $input->getArgument('name'), '->getArgument() returns the value for the given argument'); + $this->assertSame('foo', $input->getArgument('name'), '->getArgument() returns the value for the given argument'); $input->setArgument('name', 'bar'); - $this->assertEquals('bar', $input->getArgument('name'), '->setArgument() sets the value for a given argument'); - $this->assertEquals(['name' => 'bar'], $input->getArguments(), '->getArguments() returns all argument values'); + $this->assertSame('bar', $input->getArgument('name'), '->setArgument() sets the value for a given argument'); + $this->assertSame(['name' => 'bar'], $input->getArguments(), '->getArguments() returns all argument values'); $input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name'), new InputArgument('bar', InputArgument::OPTIONAL, '', 'default')])); - $this->assertEquals('default', $input->getArgument('bar'), '->getArgument() returns the default value for optional arguments'); - $this->assertEquals(['name' => 'foo', 'bar' => 'default'], $input->getArguments(), '->getArguments() returns all argument values, even optional ones'); + $this->assertSame('default', $input->getArgument('bar'), '->getArgument() returns the default value for optional arguments'); + $this->assertSame(['name' => 'foo', 'bar' => 'default'], $input->getArguments(), '->getArguments() returns all argument values, even optional ones'); } public function testSetInvalidArgument() diff --git a/Tests/Input/StringInputTest.php b/Tests/Input/StringInputTest.php index 338c1428a..92425daab 100644 --- a/Tests/Input/StringInputTest.php +++ b/Tests/Input/StringInputTest.php @@ -27,7 +27,7 @@ public function testTokenize($input, $tokens, $message) $input = new StringInput($input); $r = new \ReflectionClass(ArgvInput::class); $p = $r->getProperty('tokens'); - $this->assertEquals($tokens, $p->getValue($input), $message); + $this->assertSame($tokens, $p->getValue($input), $message); } public function testInputOptionWithGivenString() @@ -39,7 +39,7 @@ public function testInputOptionWithGivenString() // call to bind $input = new StringInput('--foo=bar'); $input->bind($definition); - $this->assertEquals('bar', $input->getOption('foo')); + $this->assertSame('bar', $input->getOption('foo')); } public static function getTokenizeData() @@ -77,12 +77,12 @@ public static function getTokenizeData() public function testToString() { $input = new StringInput('-f foo'); - $this->assertEquals('-f foo', (string) $input); + $this->assertSame('-f foo', (string) $input); $input = new StringInput('-f --bar=foo "a b c d"'); - $this->assertEquals('-f --bar=foo '.escapeshellarg('a b c d'), (string) $input); + $this->assertSame('-f --bar=foo '.escapeshellarg('a b c d'), (string) $input); $input = new StringInput('-f --bar=foo \'a b c d\' '."'A\nB\\'C'"); - $this->assertEquals('-f --bar=foo '.escapeshellarg('a b c d').' '.escapeshellarg("A\nB'C"), (string) $input); + $this->assertSame('-f --bar=foo '.escapeshellarg('a b c d').' '.escapeshellarg("A\nB'C"), (string) $input); } } From 23a1a633e4ee488f843cfac61de2f90f0d764c82 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 17 Sep 2024 08:40:29 +0200 Subject: [PATCH 49/59] [Console] Add ability to schedule alarm signals and a `console.alarm` event --- Application.php | 59 ++++++-- CHANGELOG.md | 1 + Event/ConsoleAlarmEvent.php | 47 ++++++ SignalRegistry/SignalRegistry.php | 8 ++ Tests/ApplicationTest.php | 215 +++++++++++++++++++++++++++- Tests/phpt/alarm/command_exit.phpt | 64 +++++++++ Tests/phpt/signal/command_exit.phpt | 2 +- 7 files changed, 382 insertions(+), 14 deletions(-) create mode 100644 Event/ConsoleAlarmEvent.php create mode 100644 Tests/phpt/alarm/command_exit.phpt diff --git a/Application.php b/Application.php index 868f666ae..6075a6ef5 100644 --- a/Application.php +++ b/Application.php @@ -22,6 +22,7 @@ use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Completion\CompletionSuggestions; use Symfony\Component\Console\Completion\Suggestion; +use Symfony\Component\Console\Event\ConsoleAlarmEvent; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleSignalEvent; @@ -88,6 +89,7 @@ class Application implements ResetInterface private bool $initialized = false; private ?SignalRegistry $signalRegistry = null; private array $signalsToDispatchEvent = []; + private ?int $alarmInterval = null; public function __construct( private string $name = 'UNKNOWN', @@ -97,7 +99,7 @@ public function __construct( $this->defaultCommand = 'list'; if (\defined('SIGINT') && SignalRegistry::isSupported()) { $this->signalRegistry = new SignalRegistry(); - $this->signalsToDispatchEvent = [\SIGINT, \SIGQUIT, \SIGTERM, \SIGUSR1, \SIGUSR2]; + $this->signalsToDispatchEvent = [\SIGINT, \SIGQUIT, \SIGTERM, \SIGUSR1, \SIGUSR2, \SIGALRM]; } } @@ -128,6 +130,22 @@ public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent): void $this->signalsToDispatchEvent = $signalsToDispatchEvent; } + /** + * Sets the interval to schedule a SIGALRM signal in seconds. + */ + public function setAlarmInterval(?int $seconds): void + { + $this->alarmInterval = $seconds; + $this->scheduleAlarm(); + } + + private function scheduleAlarm(): void + { + if (null !== $this->alarmInterval) { + $this->getSignalRegistry()->scheduleAlarm($this->alarmInterval); + } + } + /** * Runs the current application. * @@ -981,34 +999,47 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { - if (!$this->signalRegistry) { - throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); - } + $signalRegistry = $this->getSignalRegistry(); if (Terminal::hasSttyAvailable()) { $sttyMode = shell_exec('stty -g'); foreach ([\SIGINT, \SIGQUIT, \SIGTERM] as $signal) { - $this->signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); + $signalRegistry->register($signal, static fn () => shell_exec('stty '.$sttyMode)); } } if ($this->dispatcher) { // We register application signals, so that we can dispatch the event foreach ($this->signalsToDispatchEvent as $signal) { - $event = new ConsoleSignalEvent($command, $input, $output, $signal); - - $this->signalRegistry->register($signal, function ($signal) use ($event, $command, $commandSignals) { - $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); - $exitCode = $event->getExitCode(); + $signalEvent = new ConsoleSignalEvent($command, $input, $output, $signal); + $alarmEvent = \SIGALRM === $signal ? new ConsoleAlarmEvent($command, $input, $output) : null; + + $signalRegistry->register($signal, function ($signal) use ($signalEvent, $alarmEvent, $command, $commandSignals, $input, $output) { + $this->dispatcher->dispatch($signalEvent, ConsoleEvents::SIGNAL); + $exitCode = $signalEvent->getExitCode(); + + if (null !== $alarmEvent) { + if (false !== $exitCode) { + $alarmEvent->setExitCode($exitCode); + } else { + $alarmEvent->abortExit(); + } + $this->dispatcher->dispatch($alarmEvent); + $exitCode = $alarmEvent->getExitCode(); + } // If the command is signalable, we call the handleSignal() method if (\in_array($signal, $commandSignals, true)) { $exitCode = $command->handleSignal($signal, $exitCode); } + if (\SIGALRM === $signal) { + $this->scheduleAlarm(); + } + if (false !== $exitCode) { - $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal); + $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode, $signal); $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); exit($event->getExitCode()); @@ -1021,7 +1052,11 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI } foreach ($commandSignals as $signal) { - $this->signalRegistry->register($signal, function (int $signal) use ($command): void { + $signalRegistry->register($signal, function (int $signal) use ($command): void { + if (\SIGALRM === $signal) { + $this->scheduleAlarm(); + } + if (false !== $exitCode = $command->handleSignal($signal)) { exit($exitCode); } diff --git a/CHANGELOG.md b/CHANGELOG.md index a7b3c0450..2c963568c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG * [BC BREAK] Add silent verbosity (`--silent`/`SHELL_VERBOSITY=-2`) to suppress all output, including errors * Add `OutputInterface::isSilent()`, `Output::isSilent()`, `OutputStyle::isSilent()` methods * Add a configurable finished indicator to the progress indicator to show that the progress is finished + * Add ability to schedule alarm signals and a `ConsoleAlarmEvent` 7.1 --- diff --git a/Event/ConsoleAlarmEvent.php b/Event/ConsoleAlarmEvent.php new file mode 100644 index 000000000..876ab59b9 --- /dev/null +++ b/Event/ConsoleAlarmEvent.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Event; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +final class ConsoleAlarmEvent extends ConsoleEvent +{ + public function __construct( + Command $command, + InputInterface $input, + OutputInterface $output, + private int|false $exitCode = 0, + ) { + parent::__construct($command, $input, $output); + } + + public function setExitCode(int $exitCode): void + { + if ($exitCode < 0 || $exitCode > 255) { + throw new \InvalidArgumentException('Exit code must be between 0 and 255.'); + } + + $this->exitCode = $exitCode; + } + + public function abortExit(): void + { + $this->exitCode = false; + } + + public function getExitCode(): int|false + { + return $this->exitCode; + } +} diff --git a/SignalRegistry/SignalRegistry.php b/SignalRegistry/SignalRegistry.php index ef2e5f04e..8c2939eec 100644 --- a/SignalRegistry/SignalRegistry.php +++ b/SignalRegistry/SignalRegistry.php @@ -54,4 +54,12 @@ public function handle(int $signal): void $signalHandler($signal, $hasNext); } } + + /** + * @internal + */ + public function scheduleAlarm(int $seconds): void + { + pcntl_alarm($seconds); + } } diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index 0fa10d85a..a4ec0de7c 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -22,6 +22,7 @@ use Symfony\Component\Console\CommandLoader\FactoryCommandLoader; use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass; +use Symfony\Component\Console\Event\ConsoleAlarmEvent; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\Event\ConsoleSignalEvent; @@ -70,6 +71,9 @@ protected function tearDown(): void unset($_SERVER['SHELL_VERBOSITY']); if (\function_exists('pcntl_signal')) { + // We cancel any pending alarms + pcntl_alarm(0); + // We reset all signals to their default value to avoid side effects pcntl_signal(\SIGINT, \SIG_DFL); pcntl_signal(\SIGTERM, \SIG_DFL); @@ -2230,6 +2234,167 @@ public function testSignalableRestoresStty() $this->assertSame($previousSttyMode, $sttyMode); } + /** + * @requires extension pcntl + */ + public function testAlarmSubscriberNotCalledByDefault() + { + $command = new BaseSignableCommand(false); + + $subscriber = new AlarmEventSubscriber(); + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber($subscriber); + + $application = $this->createSignalableApplication($command, $dispatcher); + + $this->assertSame(0, $application->run(new ArrayInput(['signal']))); + $this->assertFalse($subscriber->signaled); + } + + /** + * @requires extension pcntl + */ + public function testAlarmSubscriberNotCalledForOtherSignals() + { + $command = new SignableCommand(); + + $subscriber1 = new SignalEventSubscriber(); + $subscriber2 = new AlarmEventSubscriber(); + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber($subscriber1); + $dispatcher->addSubscriber($subscriber2); + + $application = $this->createSignalableApplication($command, $dispatcher); + + $this->assertSame(1, $application->run(new ArrayInput(['signal']))); + $this->assertTrue($subscriber1->signaled); + $this->assertFalse($subscriber2->signaled); + } + + /** + * @requires extension pcntl + */ + public function testAlarmSubscriber() + { + $command = new BaseSignableCommand(signal: \SIGALRM); + + $subscriber1 = new AlarmEventSubscriber(); + $subscriber2 = new AlarmEventSubscriber(); + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber($subscriber1); + $dispatcher->addSubscriber($subscriber2); + + $application = $this->createSignalableApplication($command, $dispatcher); + + $this->assertSame(1, $application->run(new ArrayInput(['signal']))); + $this->assertTrue($subscriber1->signaled); + $this->assertTrue($subscriber2->signaled); + } + + /** + * @requires extension pcntl + */ + public function testAlarmDispatchWithoutEventDispatcher() + { + $command = new AlarmableCommand(1); + $command->loop = 11000; + + $application = $this->createSignalableApplication($command, null); + + $this->assertSame(1, $application->run(new ArrayInput(['alarm']))); + $this->assertTrue($command->signaled); + } + + /** + * @requires extension pcntl + */ + public function testAlarmableCommandWithoutInterval() + { + $command = new AlarmableCommand(0); + $command->loop = 11000; + + $dispatcher = new EventDispatcher(); + + $application = new Application(); + $application->setAutoExit(false); + $application->setDispatcher($dispatcher); + $application->add($command); + + $this->assertSame(0, $application->run(new ArrayInput(['alarm']))); + $this->assertFalse($command->signaled); + } + + /** + * @requires extension pcntl + */ + public function testAlarmableCommandHandlerCalledAfterEventListener() + { + $command = new AlarmableCommand(1); + $command->loop = 11000; + + $subscriber = new AlarmEventSubscriber(); + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber($subscriber); + + $application = $this->createSignalableApplication($command, $dispatcher); + + $this->assertSame(1, $application->run(new ArrayInput(['alarm']))); + $this->assertSame([AlarmEventSubscriber::class, AlarmableCommand::class], $command->signalHandlers); + } + + /** + * @requires extension pcntl + * + * @testWith [false] + * [4] + */ + public function testAlarmSubscriberCalledAfterSignalSubscriberAndInheritsExitCode(int|false $exitCode) + { + $command = new BaseSignableCommand(signal: \SIGALRM); + + $subscriber1 = new class($exitCode) extends SignalEventSubscriber { + public function __construct(private int|false $exitCode) + { + } + + public function onSignal(ConsoleSignalEvent $event): void + { + parent::onSignal($event); + + if (false === $this->exitCode) { + $event->abortExit(); + } else { + $event->setExitCode($this->exitCode); + } + } + }; + $subscriber2 = new class($exitCode) extends AlarmEventSubscriber { + public function __construct(private int|false $exitCode) + { + } + + public function onAlarm(ConsoleAlarmEvent $event): void + { + TestCase::assertSame($this->exitCode, $event->getExitCode()); + + parent::onAlarm($event); + } + }; + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber($subscriber1); + $dispatcher->addSubscriber($subscriber2); + + $application = $this->createSignalableApplication($command, $dispatcher); + + $this->assertSame(1, $application->run(new ArrayInput(['signal']))); + $this->assertSame([SignalEventSubscriber::class, AlarmEventSubscriber::class], $command->signalHandlers); + } + private function createSignalableApplication(Command $command, ?EventDispatcherInterface $dispatcher): Application { $application = new Application(); @@ -2237,7 +2402,7 @@ private function createSignalableApplication(Command $command, ?EventDispatcherI if ($dispatcher) { $application->setDispatcher($dispatcher); } - $application->add(new LazyCommand('signal', [], '', false, fn () => $command, true)); + $application->add(new LazyCommand($command::getDefaultName(), [], '', false, fn () => $command, true)); return $application; } @@ -2427,3 +2592,51 @@ public static function getSubscribedEvents(): array return ['console.signal' => 'onSignal']; } } + +#[AsCommand(name: 'alarm')] +class AlarmableCommand extends BaseSignableCommand implements SignalableCommandInterface +{ + public function __construct(private int $alarmInterval) + { + parent::__construct(false); + } + + protected function initialize(InputInterface $input, OutputInterface $output): void + { + $this->getApplication()->setAlarmInterval($this->alarmInterval); + } + + public function getSubscribedSignals(): array + { + return [\SIGALRM]; + } + + public function handleSignal(int $signal, false|int $previousExitCode = 0): int|false + { + if (\SIGALRM === $signal) { + $this->signaled = true; + $this->signalHandlers[] = __CLASS__; + } + + return false; + } +} + +class AlarmEventSubscriber implements EventSubscriberInterface +{ + public bool $signaled = false; + + public function onAlarm(ConsoleAlarmEvent $event): void + { + $this->signaled = true; + $event->getCommand()->signaled = true; + $event->getCommand()->signalHandlers[] = __CLASS__; + + $event->abortExit(); + } + + public static function getSubscribedEvents(): array + { + return [ConsoleAlarmEvent::class => 'onAlarm']; + } +} diff --git a/Tests/phpt/alarm/command_exit.phpt b/Tests/phpt/alarm/command_exit.phpt new file mode 100644 index 000000000..18b3fa023 --- /dev/null +++ b/Tests/phpt/alarm/command_exit.phpt @@ -0,0 +1,64 @@ +--TEST-- +Test command that exits +--SKIPIF-- + +--FILE-- +getApplication()->setAlarmInterval(1); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + sleep(5); + + $output->writeln('should not be displayed'); + + return 0; + } + + public function getSubscribedSignals(): array + { + return [\SIGALRM]; + } + + public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false + { + if (\SIGALRM === $signal) { + echo "Received alarm!"; + + return 0; + } + + return false; + } +} + +$app = new Application(); +$app->setDispatcher(new \Symfony\Component\EventDispatcher\EventDispatcher()); +$app->add(new MyCommand('foo')); + +$app + ->setDefaultCommand('foo', true) + ->run() +; +--EXPECT-- +Received alarm! diff --git a/Tests/phpt/signal/command_exit.phpt b/Tests/phpt/signal/command_exit.phpt index fde3793a8..b1a314d8a 100644 --- a/Tests/phpt/signal/command_exit.phpt +++ b/Tests/phpt/signal/command_exit.phpt @@ -1,5 +1,5 @@ --TEST-- -Test command that exist +Test command that exits --SKIPIF-- --FILE-- From de23257c024f6b7ca426ef7b5c0b6ea4efb14b13 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 6 Oct 2024 18:45:39 +0200 Subject: [PATCH 50/59] CS: clean some whitespaces/indentation --- Tests/Helper/TableTest.php | 322 ++++++++++++++++++------------------- 1 file changed, 161 insertions(+), 161 deletions(-) diff --git a/Tests/Helper/TableTest.php b/Tests/Helper/TableTest.php index 4af12e34c..608d23c21 100644 --- a/Tests/Helper/TableTest.php +++ b/Tests/Helper/TableTest.php @@ -102,7 +102,7 @@ public static function renderProvider() ['ISBN', 'Title', 'Author'], $books, 'default', -<<<'TABLE' + <<<'TABLE' +---------------+--------------------------+------------------+ | ISBN | Title | Author | +---------------+--------------------------+------------------+ @@ -191,7 +191,7 @@ public static function renderProvider() ['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+--------------------------+------------------+ | ISBN | Title | | +---------------+--------------------------+------------------+ @@ -212,7 +212,7 @@ public static function renderProvider() ['80-902734-1-6', 'And Then There Were None', 'Agatha Christie'], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+--------------------------+------------------+ | 99921-58-10-7 | Divine Comedy | Dante Alighieri | | 9971-5-0210-0 | | | @@ -231,7 +231,7 @@ public static function renderProvider() ['960-425-059-0', 'The Lord of the Rings', "J. R. R.\nTolkien"], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+----------------------------+-----------------+ | ISBN | Title | Author | +---------------+----------------------------+-----------------+ @@ -251,7 +251,7 @@ public static function renderProvider() ['ISBN', 'Title'], [], 'default', -<<<'TABLE' + <<<'TABLE' +------+-------+ | ISBN | Title | +------+-------+ @@ -271,7 +271,7 @@ public static function renderProvider() ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+----------------------+-----------------+ | ISBN | Title | Author | +---------------+----------------------+-----------------+ @@ -288,7 +288,7 @@ public static function renderProvider() ['9971-5-0210-0', 'A Tale of Two Cities', 'Charles Dickens'], ], 'default', -<<<'TABLE' + <<<'TABLE' +----------------------------------+----------------------+-----------------+ | ISBN | Title | Author | +----------------------------------+----------------------+-----------------+ @@ -320,7 +320,7 @@ public static function renderProvider() ], ], 'default', -<<<'TABLE' + <<<'TABLE' +-------------------------------+-------------------------------+-----------------------------+ | ISBN | Title | Author | +-------------------------------+-------------------------------+-----------------------------+ @@ -347,7 +347,7 @@ public static function renderProvider() ], ], 'default', -<<<'TABLE' + <<<'TABLE' +-----+-----+-----+ | Foo | Bar | Baz | +-----+-----+-----+ @@ -366,7 +366,7 @@ public static function renderProvider() ], ], 'default', -<<<'TABLE' + <<<'TABLE' +-----+-----+------+ | Foo | Bar | Baz | +-----+-----+------+ @@ -392,7 +392,7 @@ public static function renderProvider() ['80-902734-1-7', 'Test'], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+---------------+-----------------+ | ISBN | Title | Author | +---------------+---------------+-----------------+ @@ -425,7 +425,7 @@ public static function renderProvider() ['J. R. R'], ], 'default', -<<<'TABLE' + <<<'TABLE' +------------------+---------+-----------------+ | ISBN | Title | Author | +------------------+---------+-----------------+ @@ -460,7 +460,7 @@ public static function renderProvider() ], ], 'default', -<<<'TABLE' + <<<'TABLE' +-----------------+-------+-----------------+ | ISBN | Title | Author | +-----------------+-------+-----------------+ @@ -497,7 +497,7 @@ public static function renderProvider() ['Charles Dickens'], ], 'default', -<<<'TABLE' + <<<'TABLE' +-----------------+-------+-----------------+ | ISBN | Title | Author | +-----------------+-------+-----------------+ @@ -524,7 +524,7 @@ public static function renderProvider() ['Charles Dickens'], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+-----------------+ | ISBN | Author | +---------------+-----------------+ @@ -542,7 +542,7 @@ public static function renderProvider() ], [], 'default', -<<<'TABLE' + <<<'TABLE' +------+-------+--------+ | Main title | +------+-------+--------+ @@ -560,9 +560,9 @@ public static function renderProvider() new TableCell('3', ['colspan' => 2]), new TableCell('4', ['colspan' => 2]), ], - ], + ], 'default', -<<<'TABLE' + <<<'TABLE' +---+--+--+---+--+---+--+---+--+ | 1 | 2 | 3 | 4 | +---+--+--+---+--+---+--+---+--+ @@ -595,7 +595,7 @@ public static function renderProvider() +-----------------+------------------+---------+ TABLE - , + , true, ], 'Row with formatted cells containing a newline' => [ @@ -607,7 +607,7 @@ public static function renderProvider() new TableSeparator(), [ 'foo', - new TableCell('Dont break'."\n".'here', ['rowspan' => 2]), + new TableCell('Dont break'."\n".'here', ['rowspan' => 2]), ], [ 'bar', @@ -624,77 +624,77 @@ public static function renderProvider() +-------+------------+ TABLE - , + , true, ], 'TabeCellStyle with align. Also with rowspan and colspan > 1' => [ - [ - new TableCell( - 'ISBN', - [ - 'style' => new TableCellStyle([ - 'align' => 'right', - ]), - ] - ), - 'Title', - new TableCell( - 'Author', - [ - 'style' => new TableCellStyle([ - 'align' => 'center', - ]), - ] - ), - ], - [ - [ - new TableCell( - '978', - [ - 'style' => new TableCellStyle([ - 'align' => 'center', - ]), - ] - ), - 'De Monarchia', - new TableCell( - "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows", - [ - 'rowspan' => 2, - 'style' => new TableCellStyle([ - 'align' => 'center', - ]), - ] - ), - ], - [ - '99921-58-10-7', - 'Divine Comedy', - ], - new TableSeparator(), - [ - new TableCell( - 'test', - [ - 'colspan' => 2, - 'style' => new TableCellStyle([ - 'align' => 'center', - ]), - ] - ), - new TableCell( - 'tttt', - [ - 'style' => new TableCellStyle([ - 'align' => 'right', - ]), - ] - ), - ], - ], - 'default', -<<<'TABLE' + [ + new TableCell( + 'ISBN', + [ + 'style' => new TableCellStyle([ + 'align' => 'right', + ]), + ] + ), + 'Title', + new TableCell( + 'Author', + [ + 'style' => new TableCellStyle([ + 'align' => 'center', + ]), + ] + ), + ], + [ + [ + new TableCell( + '978', + [ + 'style' => new TableCellStyle([ + 'align' => 'center', + ]), + ] + ), + 'De Monarchia', + new TableCell( + "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows", + [ + 'rowspan' => 2, + 'style' => new TableCellStyle([ + 'align' => 'center', + ]), + ] + ), + ], + [ + '99921-58-10-7', + 'Divine Comedy', + ], + new TableSeparator(), + [ + new TableCell( + 'test', + [ + 'colspan' => 2, + 'style' => new TableCellStyle([ + 'align' => 'center', + ]), + ] + ), + new TableCell( + 'tttt', + [ + 'style' => new TableCellStyle([ + 'align' => 'right', + ]), + ] + ), + ], + ], + 'default', + <<<'TABLE' +---------------+---------------+-------------------------------------------+ | ISBN | Title | Author | +---------------+---------------+-------------------------------------------+ @@ -706,66 +706,66 @@ public static function renderProvider() +---------------+---------------+-------------------------------------------+ TABLE - , - ], + , + ], 'TabeCellStyle with fg,bg. Also with rowspan and colspan > 1' => [ [], [ - [ - new TableCell( - '978', - [ - 'style' => new TableCellStyle([ - 'fg' => 'black', - 'bg' => 'green', - ]), - ] - ), - 'De Monarchia', - new TableCell( - "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows", - [ - 'rowspan' => 2, - 'style' => new TableCellStyle([ - 'fg' => 'red', - 'bg' => 'green', - 'align' => 'center', - ]), - ] - ), - ], - - [ - '99921-58-10-7', - 'Divine Comedy', - ], - new TableSeparator(), - [ - new TableCell( - 'test', - [ - 'colspan' => 2, - 'style' => new TableCellStyle([ - 'fg' => 'red', - 'bg' => 'green', - 'align' => 'center', - ]), - ] - ), - new TableCell( - 'tttt', - [ - 'style' => new TableCellStyle([ - 'fg' => 'red', - 'bg' => 'green', - 'align' => 'right', - ]), - ] - ), - ], + [ + new TableCell( + '978', + [ + 'style' => new TableCellStyle([ + 'fg' => 'black', + 'bg' => 'green', + ]), + ] + ), + 'De Monarchia', + new TableCell( + "Dante Alighieri \nspans multiple rows rows Dante Alighieri \nspans multiple rows rows", + [ + 'rowspan' => 2, + 'style' => new TableCellStyle([ + 'fg' => 'red', + 'bg' => 'green', + 'align' => 'center', + ]), + ] + ), + ], + + [ + '99921-58-10-7', + 'Divine Comedy', + ], + new TableSeparator(), + [ + new TableCell( + 'test', + [ + 'colspan' => 2, + 'style' => new TableCellStyle([ + 'fg' => 'red', + 'bg' => 'green', + 'align' => 'center', + ]), + ] + ), + new TableCell( + 'tttt', + [ + 'style' => new TableCellStyle([ + 'fg' => 'red', + 'bg' => 'green', + 'align' => 'right', + ]), + ] + ), + ], ], 'default', -<<<'TABLE' + <<<'TABLE' +---------------+---------------+-------------------------------------------+ | 978 | De Monarchia | Dante Alighieri | | 99921-58-10-7 | Divine Comedy | spans multiple rows rows Dante Alighieri | @@ -775,9 +775,9 @@ public static function renderProvider() +---------------+---------------+-------------------------------------------+ TABLE - , - true, - ], + , + true, + ], 'TabeCellStyle with cellFormat. Also with rowspan and colspan > 1' => [ [ new TableCell( @@ -820,7 +820,7 @@ public static function renderProvider() ], ], 'default', -<<<'TABLE' + <<<'TABLE' +----------------+---------------+---------------------+ | ISBN | Title | Author | +----------------+---------------+---------------------+ @@ -832,7 +832,7 @@ public static function renderProvider() TABLE , true, - ], + ], ]; } @@ -1288,7 +1288,7 @@ public static function renderSetTitle() TABLE , true, - ], + ], 'header contains multiple lines' => [ 'Multiline'."\n".'header'."\n".'here', 'footer', @@ -1558,18 +1558,18 @@ public function testWithColspanAndMaxWith() $table->setColumnMaxWidth(1, 15); $table->setColumnMaxWidth(2, 15); $table->setRows([ - [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])], - new TableSeparator(), - [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])], - new TableSeparator(), - [new TableCell('Lorem ipsum dolor sit amet, consectetur ', ['colspan' => 2]), 'hello world'], - new TableSeparator(), - ['hello world', new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit', ['colspan' => 2])], - new TableSeparator(), - ['hello ', new TableCell('world', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'], - new TableSeparator(), - ['Symfony ', new TableCell('Test', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'], - ]) + [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])], + new TableSeparator(), + [new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor', ['colspan' => 3])], + new TableSeparator(), + [new TableCell('Lorem ipsum dolor sit amet, consectetur ', ['colspan' => 2]), 'hello world'], + new TableSeparator(), + ['hello world', new TableCell('Lorem ipsum dolor sit amet, consectetur adipiscing elit', ['colspan' => 2])], + new TableSeparator(), + ['hello ', new TableCell('world', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'], + new TableSeparator(), + ['Symfony ', new TableCell('Test', ['colspan' => 1]), 'Lorem ipsum dolor sit amet, consectetur'], + ]) ; $table->render(); From a97129d215b0730fe86c59f1ceefc6ad2e93533d Mon Sep 17 00:00:00 2001 From: valtzu Date: Sun, 13 Oct 2024 15:18:50 +0300 Subject: [PATCH 51/59] Add `$seconds` to `keepalive` methods --- Application.php | 8 ++++++++ Tests/ApplicationTest.php | 1 + 2 files changed, 9 insertions(+) diff --git a/Application.php b/Application.php index 6075a6ef5..2ed1319cb 100644 --- a/Application.php +++ b/Application.php @@ -139,6 +139,14 @@ public function setAlarmInterval(?int $seconds): void $this->scheduleAlarm(); } + /** + * Gets the interval in seconds on which a SIGALRM signal is dispatched. + */ + public function getAlarmInterval(): ?int + { + return $this->alarmInterval; + } + private function scheduleAlarm(): void { if (null !== $this->alarmInterval) { diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index a4ec0de7c..469353505 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -2305,6 +2305,7 @@ public function testAlarmDispatchWithoutEventDispatcher() $application = $this->createSignalableApplication($command, null); $this->assertSame(1, $application->run(new ArrayInput(['alarm']))); + $this->assertSame(1, $application->getAlarmInterval()); $this->assertTrue($command->signaled); } From 8f6d3ecb5ae72d1f21af58fc7ec50a4d9e4273e4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 14 Oct 2024 20:03:05 +0200 Subject: [PATCH 52/59] Reduce common control flows --- Completion/CompletionInput.php | 4 ++-- Tests/Logger/ConsoleLoggerTest.php | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Completion/CompletionInput.php b/Completion/CompletionInput.php index 50febf2de..9f9619e18 100644 --- a/Completion/CompletionInput.php +++ b/Completion/CompletionInput.php @@ -123,13 +123,13 @@ public function bind(InputDefinition $definition): void if ($this->currentIndex >= \count($this->tokens)) { if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) { $this->completionName = $argumentName; - $this->completionValue = ''; } else { // we've reached the end $this->completionType = self::TYPE_NONE; $this->completionName = null; - $this->completionValue = ''; } + + $this->completionValue = ''; } } diff --git a/Tests/Logger/ConsoleLoggerTest.php b/Tests/Logger/ConsoleLoggerTest.php index 43d779631..0464c8c5f 100644 --- a/Tests/Logger/ConsoleLoggerTest.php +++ b/Tests/Logger/ConsoleLoggerTest.php @@ -151,11 +151,7 @@ public function testContextReplacement() public function testObjectCastToString() { - if (method_exists($this, 'createPartialMock')) { - $dummy = $this->createPartialMock(DummyTest::class, ['__toString']); - } else { - $dummy = $this->createPartialMock(DummyTest::class, ['__toString']); - } + $dummy = $this->createPartialMock(DummyTest::class, ['__toString']); $dummy->method('__toString')->willReturn('DUMMY'); $this->getLogger()->warning($dummy); From de74db6d7c9f4ecabf7b4a1a20655e021b034001 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 18 Oct 2024 16:04:52 +0200 Subject: [PATCH 53/59] Remove always true/false occurrences --- DependencyInjection/AddConsoleCommandPass.php | 2 +- SingleCommandApplication.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DependencyInjection/AddConsoleCommandPass.php b/DependencyInjection/AddConsoleCommandPass.php index 642247e3f..f1521602a 100644 --- a/DependencyInjection/AddConsoleCommandPass.php +++ b/DependencyInjection/AddConsoleCommandPass.php @@ -53,7 +53,7 @@ public function process(ContainerBuilder $container): void $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); } - $aliases = explode('|', $aliases ?? ''); + $aliases = explode('|', $aliases); $commandName = array_shift($aliases); if ($isHidden = '' === $commandName) { diff --git a/SingleCommandApplication.php b/SingleCommandApplication.php index ff1c17247..2b54fb870 100644 --- a/SingleCommandApplication.php +++ b/SingleCommandApplication.php @@ -67,6 +67,6 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu $this->running = false; } - return $ret ?? 1; + return $ret; } } From c32691c80952990ee151c054f62d09aceeece23b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 27 Oct 2024 07:46:44 +0100 Subject: [PATCH 54/59] Don't use `die()` in PHPT `--SKIPIF--` Unlocks a performance optimization in PHPUnit 11.x see https://staabm.github.io/2024/10/19/phpunit-codesprint-munich.html --- Tests/phpt/alarm/command_exit.phpt | 2 +- Tests/phpt/signal/command_exit.phpt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/phpt/alarm/command_exit.phpt b/Tests/phpt/alarm/command_exit.phpt index 18b3fa023..d3015ad9d 100644 --- a/Tests/phpt/alarm/command_exit.phpt +++ b/Tests/phpt/alarm/command_exit.phpt @@ -1,7 +1,7 @@ --TEST-- Test command that exits --SKIPIF-- - + --FILE-- + --FILE-- Date: Mon, 2 Dec 2024 14:51:36 +0100 Subject: [PATCH 55/59] [Console] Fix division by 0 error --- Helper/ProgressBar.php | 2 +- Tests/Helper/ProgressBarTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index b406292b4..23157e3c7 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -229,7 +229,7 @@ public function getEstimated(): float public function getRemaining(): float { - if (!$this->step) { + if (0 === $this->step || $this->step === $this->startingStep) { return 0; } diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index a5a0eca24..c32307720 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -110,6 +110,14 @@ public function testRegularTimeEstimation() ); } + public function testRegularTimeRemainingWithDifferentStartAtAndCustomDisplay() + { + ProgressBar::setFormatDefinition('custom', ' %current%/%max% [%bar%] %percent:3s%% %remaining% %estimated%'); + $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); + $bar->setFormat('custom'); + $bar->start(1_200, 600); + } + public function testResumedTimeEstimation() { $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); From 799445db3f15768ecc382ac5699e6da0520a0a04 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 7 Dec 2024 13:07:30 +0100 Subject: [PATCH 56/59] fix risky test that doesn't perform any assertions --- Tests/Helper/ProgressBarTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index c32307720..a1db94583 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -112,8 +112,10 @@ public function testRegularTimeEstimation() public function testRegularTimeRemainingWithDifferentStartAtAndCustomDisplay() { + $this->expectNotToPerformAssertions(); + ProgressBar::setFormatDefinition('custom', ' %current%/%max% [%bar%] %percent:3s%% %remaining% %estimated%'); - $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); + $bar = new ProgressBar($this->getOutputStream(), 1_200, 0); $bar->setFormat('custom'); $bar->start(1_200, 600); } From fefcc18c0f5d0efe3ab3152f15857298868dc2c3 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 11 Dec 2024 04:49:26 +0100 Subject: [PATCH 57/59] [Console] Fix tests --- Tests/ApplicationTest.php | 1 + Tests/ConsoleEventsTest.php | 1 + Tests/SignalRegistry/SignalRegistryTest.php | 1 + 3 files changed, 3 insertions(+) diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index 469353505..4f6e6cb96 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -79,6 +79,7 @@ protected function tearDown(): void pcntl_signal(\SIGTERM, \SIG_DFL); pcntl_signal(\SIGUSR1, \SIG_DFL); pcntl_signal(\SIGUSR2, \SIG_DFL); + pcntl_signal(\SIGALRM, \SIG_DFL); } } diff --git a/Tests/ConsoleEventsTest.php b/Tests/ConsoleEventsTest.php index 9c04d2706..408f8c0d3 100644 --- a/Tests/ConsoleEventsTest.php +++ b/Tests/ConsoleEventsTest.php @@ -39,6 +39,7 @@ protected function tearDown(): void pcntl_signal(\SIGTERM, \SIG_DFL); pcntl_signal(\SIGUSR1, \SIG_DFL); pcntl_signal(\SIGUSR2, \SIG_DFL); + pcntl_signal(\SIGALRM, \SIG_DFL); } } diff --git a/Tests/SignalRegistry/SignalRegistryTest.php b/Tests/SignalRegistry/SignalRegistryTest.php index f997f7c1d..92d500f9e 100644 --- a/Tests/SignalRegistry/SignalRegistryTest.php +++ b/Tests/SignalRegistry/SignalRegistryTest.php @@ -27,6 +27,7 @@ protected function tearDown(): void pcntl_signal(\SIGTERM, \SIG_DFL); pcntl_signal(\SIGUSR1, \SIG_DFL); pcntl_signal(\SIGUSR2, \SIG_DFL); + pcntl_signal(\SIGALRM, \SIG_DFL); } public function testOneCallbackForASignalSignalIsHandled() From 2e4af9c952617cc3f9559ff706aee420a8464c36 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Thu, 27 Feb 2025 11:59:51 +0100 Subject: [PATCH 58/59] fix(console): fix progress bar messing output in section when there is an EOL --- Helper/ProgressBar.php | 9 ++++ Tests/Helper/ProgressBarTest.php | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index 23157e3c7..3dc06d7b4 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -486,12 +486,21 @@ private function overwrite(string $message): void if ($this->output instanceof ConsoleSectionOutput) { $messageLines = explode("\n", $this->previousMessage); $lineCount = \count($messageLines); + + $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? ''); + + // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again + if ('' === $lastLineWithoutDecoration) { + --$lineCount; + } + foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += floor($messageLineLength / $this->terminal->getWidth()); } } + $this->output->clear($lineCount); } else { $lineCount = substr_count($this->previousMessage, "\n"); diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index a1db94583..615237f1f 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -416,6 +416,81 @@ public function testOverwriteWithSectionOutput() ); } + public function testOverwriteWithSectionOutputAndEol() + { + $sections = []; + $stream = $this->getOutputStream(true); + $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); + + $bar = new ProgressBar($output, 50, 0); + $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%' . PHP_EOL); + $bar->setMessage(''); + $bar->start(); + $bar->display(); + $bar->setMessage('Doing something...'); + $bar->advance(); + $bar->setMessage('Doing something foo...'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd( + '[>---------------------------] 0%'.\PHP_EOL.\PHP_EOL. + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL. 'Doing something...' . \PHP_EOL . + "\x1b[2A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something foo...' . \PHP_EOL), + escapeshellcmd(stream_get_contents($output->getStream())) + ); + } + + public function testOverwriteWithSectionOutputAndEolWithEmptyMessage() + { + $sections = []; + $stream = $this->getOutputStream(true); + $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); + + $bar = new ProgressBar($output, 50, 0); + $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%'); + $bar->setMessage('Start'); + $bar->start(); + $bar->display(); + $bar->setMessage(''); + $bar->advance(); + $bar->setMessage('Doing something...'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd( + '[>---------------------------] 0%'.\PHP_EOL.'Start'.\PHP_EOL. + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL . + "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something...' . \PHP_EOL), + escapeshellcmd(stream_get_contents($output->getStream())) + ); + } + + public function testOverwriteWithSectionOutputAndEolWithEmptyMessageComment() + { + $sections = []; + $stream = $this->getOutputStream(true); + $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); + + $bar = new ProgressBar($output, 50, 0); + $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%'); + $bar->setMessage('Start'); + $bar->start(); + $bar->display(); + $bar->setMessage(''); + $bar->advance(); + $bar->setMessage('Doing something...'); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals(escapeshellcmd( + '[>---------------------------] 0%'.\PHP_EOL."\x1b[33mStart\x1b[39m".\PHP_EOL. + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL . + "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. "\x1b[33mDoing something...\x1b[39m" . \PHP_EOL), + escapeshellcmd(stream_get_contents($output->getStream())) + ); + } + public function testOverwriteWithAnsiSectionOutput() { // output has 43 visible characters plus 2 invisible ANSI characters From a3011c7b7adb58d89f6c0d822abb641d7a5f9719 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Mon, 7 Apr 2025 16:42:41 +0100 Subject: [PATCH 59/59] Correctly convert SIGSYS to its name --- SignalRegistry/SignalMap.php | 2 +- Tests/SignalRegistry/SignalMapTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SignalRegistry/SignalMap.php b/SignalRegistry/SignalMap.php index de419bda7..2f9aa67c1 100644 --- a/SignalRegistry/SignalMap.php +++ b/SignalRegistry/SignalMap.php @@ -27,7 +27,7 @@ public static function getSignalName(int $signal): ?string if (!isset(self::$map)) { $r = new \ReflectionExtension('pcntl'); $c = $r->getConstants(); - $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_'), \ARRAY_FILTER_USE_KEY); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY); self::$map = array_flip($map); } diff --git a/Tests/SignalRegistry/SignalMapTest.php b/Tests/SignalRegistry/SignalMapTest.php index 887c5d7af..f4e320477 100644 --- a/Tests/SignalRegistry/SignalMapTest.php +++ b/Tests/SignalRegistry/SignalMapTest.php @@ -22,6 +22,7 @@ class SignalMapTest extends TestCase * @testWith [2, "SIGINT"] * [9, "SIGKILL"] * [15, "SIGTERM"] + * [31, "SIGSYS"] */ public function testSignalExists(int $signal, string $expected) {