Skip to content

Commit 4ae5cbe

Browse files
Add Lazy Command Support
1 parent de268d2 commit 4ae5cbe

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

src/Symfony/ConsoleApplicationResolver.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,17 @@ public function findCommands(ClassReflection $classReflection): array
5454

5555
$commands = [];
5656
foreach ($this->consoleApplication->all() as $name => $command) {
57-
if (!$classType->isSuperTypeOf(new ObjectType(get_class($command)))->yes()) {
57+
$commandClass = new ObjectType(get_class($command));
58+
$isLazyCommand = (new ObjectType('Symfony\Component\Console\Command\LazyCommand'))->isSuperTypeOf($commandClass)->yes();
59+
60+
if ($isLazyCommand && method_exists($command, 'getCommand') && !$classType->isSuperTypeOf(new ObjectType(get_class($command->getCommand())))->yes()) {
5861
continue;
5962
}
63+
64+
if (!$isLazyCommand && !$classType->isSuperTypeOf($commandClass)->yes()) {
65+
continue;
66+
}
67+
6068
$commands[$name] = $command;
6169
}
6270

tests/Type/Symfony/ExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function dataFileAsserts(): iterable
2222
yield from $this->gatherAssertTypes(__DIR__ . '/data/tree_builder.php');
2323
yield from $this->gatherAssertTypes(__DIR__ . '/data/ExampleBaseCommand.php');
2424
yield from $this->gatherAssertTypes(__DIR__ . '/data/ExampleOptionCommand.php');
25+
yield from $this->gatherAssertTypes(__DIR__ . '/data/ExampleOptionLazyCommand.php');
2526
yield from $this->gatherAssertTypes(__DIR__ . '/data/kernel_interface.php');
2627
yield from $this->gatherAssertTypes(__DIR__ . '/data/request_get_content.php');
2728

tests/Type/Symfony/console_application_loader.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@
33
use PHPStan\Type\Symfony\ExampleACommand;
44
use PHPStan\Type\Symfony\ExampleBCommand;
55
use PHPStan\Type\Symfony\ExampleOptionCommand;
6+
use PHPStan\Type\Symfony\ExampleOptionLazyCommand;
67
use Symfony\Component\Console\Application;
8+
use Symfony\Component\Console\Command\LazyCommand;
79

810
require_once __DIR__ . '/../../../vendor/autoload.php';
911

1012
$application = new Application();
1113
$application->add(new ExampleACommand());
1214
$application->add(new ExampleBCommand());
1315
$application->add(new ExampleOptionCommand());
16+
17+
if (class_exists(LazyCommand::class)) {
18+
$application->add(new LazyCommand('lazy-example-option', [], '', false, function () {
19+
return new ExampleOptionLazyCommand();
20+
}));
21+
} else {
22+
$application->add(new ExampleOptionLazyCommand());
23+
}
24+
1425
return $application;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Symfony;
4+
5+
use Symfony\Component\Console\Command\Command;
6+
use Symfony\Component\Console\Input\InputInterface;
7+
use Symfony\Component\Console\Input\InputOption;
8+
use Symfony\Component\Console\Output\OutputInterface;
9+
use function PHPStan\Testing\assertType;
10+
11+
final class ExampleOptionLazyCommand extends Command
12+
{
13+
14+
protected static $defaultName = 'lazy-example-option';
15+
protected static $defaultDescription = 'lazy example description';
16+
17+
protected function configure(): void
18+
{
19+
parent::configure();
20+
21+
$this->addOption('a', null, InputOption::VALUE_NONE);
22+
$this->addOption('b', null, InputOption::VALUE_OPTIONAL);
23+
$this->addOption('c', null, InputOption::VALUE_REQUIRED);
24+
$this->addOption('d', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL);
25+
$this->addOption('e', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED);
26+
27+
$this->addOption('bb', null, InputOption::VALUE_OPTIONAL, '', 1);
28+
$this->addOption('cc', null, InputOption::VALUE_REQUIRED, '', 1);
29+
$this->addOption('dd', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, '', [1]);
30+
$this->addOption('ee', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, '', [1]);
31+
}
32+
33+
protected function execute(InputInterface $input, OutputInterface $output): int
34+
{
35+
assertType('bool', $input->getOption('a'));
36+
assertType('string|null', $input->getOption('b'));
37+
assertType('string|null', $input->getOption('c'));
38+
assertType('array<int, string|null>', $input->getOption('d'));
39+
assertType('array<int, string>', $input->getOption('e'));
40+
41+
assertType('1|string|null', $input->getOption('bb'));
42+
assertType('1|string', $input->getOption('cc'));
43+
assertType('array<int, 1|string|null>', $input->getOption('dd'));
44+
assertType('array<int, 1|string>', $input->getOption('ee'));
45+
}
46+
47+
}

0 commit comments

Comments
 (0)