Browse Source

Add suport for using ID for commands executed within commands.

ADmad 1 year ago
parent
commit
6d11ce0548

+ 13 - 1
src/Console/BaseCommand.php

@@ -47,6 +47,18 @@ abstract class BaseCommand implements CommandInterface, EventDispatcherInterface
      */
     protected string $name = 'cake unknown';
 
+    protected ?CommandFactoryInterface $factory = null;
+
+    /**
+     * Constructor
+     *
+     * @param \Cake\Console\CommandFactoryInterface $factory Command factory instance.
+     */
+    public function __construct(?CommandFactoryInterface $factory = null)
+    {
+        $this->factory = $factory;
+    }
+
     /**
      * @inheritDoc
      */
@@ -276,7 +288,7 @@ abstract class BaseCommand implements CommandInterface, EventDispatcherInterface
                 sprintf('Command `%s` is not a subclass of `%s`.', $command, CommandInterface::class)
             );
 
-            $command = new $command();
+            $command = $this->factory?->create($command) ?? new $command();
         }
         $io = $io ?: new ConsoleIo();
 

+ 2 - 2
src/Console/CommandFactory.php

@@ -44,11 +44,11 @@ class CommandFactory implements CommandFactoryInterface
      */
     public function create(string $className): CommandInterface
     {
-        if ($this->container && $this->container->has($className)) {
+        if ($this->container?->has($className)) {
             return $this->container->get($className);
         }
 
         /** @var \Cake\Console\CommandInterface */
-        return new $className();
+        return new $className($this);
     }
 }

+ 4 - 0
src/Console/CommandRunner.php

@@ -346,7 +346,11 @@ class CommandRunner implements EventDispatcherInterface
             if ($this->app instanceof ContainerApplicationInterface) {
                 $container = $this->app->getContainer();
             }
+
             $this->factory = new CommandFactory($container);
+            if ($container !== null) {
+                $container->add(CommandFactoryInterface::class, $this->factory);
+            }
         }
 
         return $this->factory->create($className);

+ 25 - 0
tests/TestCase/Console/CommandTest.php

@@ -18,18 +18,23 @@ namespace Cake\Test\TestCase\Console;
 
 use AssertionError;
 use Cake\Command\Command;
+use Cake\Console\CommandFactory;
+use Cake\Console\CommandFactoryInterface;
 use Cake\Console\CommandInterface;
 use Cake\Console\ConsoleIo;
 use Cake\Console\ConsoleOptionParser;
 use Cake\Console\Exception\StopException;
 use Cake\Console\TestSuite\StubConsoleOutput;
+use Cake\Core\Container;
 use Cake\ORM\Locator\TableLocator;
 use Cake\ORM\Table;
 use Cake\TestSuite\TestCase;
 use Mockery;
+use stdClass;
 use TestApp\Command\AbortCommand;
 use TestApp\Command\AutoLoadModelCommand;
 use TestApp\Command\DemoCommand;
+use TestApp\Command\DependencyCommand;
 use TestApp\Command\NonInteractiveCommand;
 
 /**
@@ -309,6 +314,26 @@ class CommandTest extends TestCase
         $this->assertEquals(['Result: Default!'], $output->messages());
     }
 
+    public function testExecuteCommandWithDI(): void
+    {
+        $output = new StubConsoleOutput();
+        $container = new Container();
+        $factory = new CommandFactory($container);
+
+        $container->add(CommandFactoryInterface::class, $factory);
+        $container->add(Command::class)
+            ->addArgument(CommandFactoryInterface::class);
+        $container->add(stdClass::class);
+        $container->add(DependencyCommand::class)
+            ->addArgument(stdClass::class);
+
+        $command = $factory->create(Command::class);
+        $result = $command->executeCommand(DependencyCommand::class, [], $this->getMockIo($output));
+
+        $this->assertSame(Command::CODE_SUCCESS, $result);
+        $this->assertEquals(['Dependency Command', 'constructor inject: {}'], $output->messages());
+    }
+
     /**
      * @param \Cake\Console\ConsoleOutput $output
      * @return \Cake\Console\ConsoleIo|\Mockery\MockInterface