diff --git a/src/Symfony/ConsoleApplicationResolver.php b/src/Symfony/ConsoleApplicationResolver.php index 88ee908f..cc4ece4e 100644 --- a/src/Symfony/ConsoleApplicationResolver.php +++ b/src/Symfony/ConsoleApplicationResolver.php @@ -54,9 +54,17 @@ public function findCommands(ClassReflection $classReflection): array $commands = []; foreach ($this->consoleApplication->all() as $name => $command) { - if (!$classType->isSuperTypeOf(new ObjectType(get_class($command)))->yes()) { + $commandClass = new ObjectType(get_class($command)); + $isLazyCommand = (new ObjectType('Symfony\Component\Console\Command\LazyCommand'))->isSuperTypeOf($commandClass)->yes(); + + if ($isLazyCommand && method_exists($command, 'getCommand') && !$classType->isSuperTypeOf(new ObjectType(get_class($command->getCommand())))->yes()) { continue; } + + if (!$isLazyCommand && !$classType->isSuperTypeOf($commandClass)->yes()) { + continue; + } + $commands[$name] = $command; } diff --git a/tests/Type/Symfony/ExtensionTest.php b/tests/Type/Symfony/ExtensionTest.php index a2de90ec..8ee9aced 100644 --- a/tests/Type/Symfony/ExtensionTest.php +++ b/tests/Type/Symfony/ExtensionTest.php @@ -22,6 +22,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/tree_builder.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/ExampleBaseCommand.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/ExampleOptionCommand.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/ExampleOptionLazyCommand.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/kernel_interface.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/request_get_content.php'); diff --git a/tests/Type/Symfony/console_application_loader.php b/tests/Type/Symfony/console_application_loader.php index 524bc159..0ef2e0ae 100644 --- a/tests/Type/Symfony/console_application_loader.php +++ b/tests/Type/Symfony/console_application_loader.php @@ -3,7 +3,9 @@ use PHPStan\Type\Symfony\ExampleACommand; use PHPStan\Type\Symfony\ExampleBCommand; use PHPStan\Type\Symfony\ExampleOptionCommand; +use PHPStan\Type\Symfony\ExampleOptionLazyCommand; use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\LazyCommand; require_once __DIR__ . '/../../../vendor/autoload.php'; @@ -11,4 +13,13 @@ $application->add(new ExampleACommand()); $application->add(new ExampleBCommand()); $application->add(new ExampleOptionCommand()); + +if (class_exists(LazyCommand::class)) { + $application->add(new LazyCommand('lazy-example-option', [], '', false, function () { + return new ExampleOptionLazyCommand(); + })); +} else { + $application->add(new ExampleOptionLazyCommand()); +} + return $application; diff --git a/tests/Type/Symfony/data/ExampleOptionLazyCommand.php b/tests/Type/Symfony/data/ExampleOptionLazyCommand.php new file mode 100644 index 00000000..7933cd41 --- /dev/null +++ b/tests/Type/Symfony/data/ExampleOptionLazyCommand.php @@ -0,0 +1,47 @@ +addOption('a', null, InputOption::VALUE_NONE); + $this->addOption('b', null, InputOption::VALUE_OPTIONAL); + $this->addOption('c', null, InputOption::VALUE_REQUIRED); + $this->addOption('d', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL); + $this->addOption('e', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED); + + $this->addOption('bb', null, InputOption::VALUE_OPTIONAL, '', 1); + $this->addOption('cc', null, InputOption::VALUE_REQUIRED, '', 1); + $this->addOption('dd', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, '', [1]); + $this->addOption('ee', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, '', [1]); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + assertType('bool', $input->getOption('a')); + assertType('string|null', $input->getOption('b')); + assertType('string|null', $input->getOption('c')); + assertType('array', $input->getOption('d')); + assertType('array', $input->getOption('e')); + + assertType('1|string|null', $input->getOption('bb')); + assertType('1|string', $input->getOption('cc')); + assertType('array', $input->getOption('dd')); + assertType('array', $input->getOption('ee')); + } + +}