Browse Source

Add Command factory support.

Makes it easier to use a custom factory, for example with DIC support.
Robert Pustułka 8 years ago
parent
commit
7ebc6af1ed

+ 39 - 0
src/Console/CommandFactory.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Console;
+
+use InvalidArgumentException;
+
+class CommandFactory implements CommandFactoryInterface
+{
+
+    /**
+     * {@inheritDoc}
+     */
+    public function create($className, ConsoleIo $io)
+    {
+        if (is_subclass_of($className, Shell::class)) {
+            return new $className($io);
+        }
+
+        // Command class
+        $command = new $className();
+        if (!$command instanceof Command) {
+            $valid = implode('` or `', [Shell::class, Command::class]);
+            $message = sprintf('Class `%s` must be an instance of `%s`.', $className, $valid);
+            throw new InvalidArgumentException($message);
+        }
+
+        return $command;
+    }
+}

+ 28 - 0
src/Console/CommandFactoryInterface.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Console;
+
+/**
+ * An interface for abstracting creation of command and shell instances.
+ */
+interface CommandFactoryInterface
+{
+    /**
+     * The factory method for creating Command and Shell instances.
+     *
+     * @param string $className Command/Shell class name.
+     * @param \Cake\Console\ConsoleIo $io The IO wrapper for the created shell class.
+     * @return \Cake\Console\Shell|\Cake\Console\Command
+     */
+    public function create($className, ConsoleIo $io);
+}

+ 11 - 7
src/Console/CommandRunner.php

@@ -43,6 +43,13 @@ class CommandRunner implements EventDispatcherInterface
     protected $app;
 
     /**
+     * The application console commands are being run for.
+     *
+     * @var \Cake\Console\CommandFactoryInterface
+     */
+    protected $factory;
+
+    /**
      * The root command name. Defaults to `cake`.
      *
      * @var string
@@ -61,11 +68,13 @@ class CommandRunner implements EventDispatcherInterface
      *
      * @param \Cake\Core\ConsoleApplicationInterface $app The application to run CLI commands for.
      * @param string $root The root command name to be removed from argv.
+     * @param \Cake\Console\CommandFactoryInterface $factory Command factory instance.
      */
-    public function __construct(ConsoleApplicationInterface $app, $root = 'cake')
+    public function __construct(ConsoleApplicationInterface $app, $root = 'cake', CommandFactoryInterface $factory = null)
     {
         $this->setApp($app);
         $this->root = $root;
+        $this->factory = $factory ?: new CommandFactory();
         $this->aliases = [
             '--version' => 'version',
             '--help' => 'help',
@@ -276,11 +285,6 @@ class CommandRunner implements EventDispatcherInterface
      */
     protected function createShell($className, ConsoleIo $io)
     {
-        if (is_subclass_of($className, Shell::class)) {
-            return new $className($io);
-        }
-
-        // Command class
-        return new $className();
+        return $this->factory->create($className, $io);
     }
 }

+ 52 - 0
tests/TestCase/Console/CommandFactoryTest.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Test\TestCase\Console;
+
+use Cake\Console\CommandFactory;
+use Cake\Console\ConsoleIo;
+use Cake\TestSuite\TestCase;
+use InvalidArgumentException;
+use TestApp\Command\DemoCommand;
+use TestApp\Shell\SampleShell;
+
+class CommandFactoryTest extends TestCase
+{
+    public function testCreateCommand()
+    {
+        $factory = new CommandFactory();
+
+        $command = $factory->create(DemoCommand::class, new ConsoleIo());
+        $this->assertInstanceOf(DemoCommand::class, $command);
+    }
+
+    public function testCreateShell()
+    {
+        $factory = new CommandFactory();
+
+        $io = new ConsoleIo();
+        $shell = $factory->create(SampleShell::class, $io);
+
+        $this->assertInstanceOf(SampleShell::class, $shell);
+        $this->assertSame($io, $shell->getIo());
+    }
+
+    public function testInvalid()
+    {
+        $factory = new CommandFactory();
+
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Class `Cake\Test\TestCase\Console\CommandFactoryTest` must be an instance of `Cake\Console\Shell` or `Cake\Console\Command`.');
+
+        $factory->create(static::class, new ConsoleIo());
+    }
+}

+ 26 - 0
tests/TestCase/Console/CommandRunnerTest.php

@@ -15,6 +15,7 @@
 namespace Cake\Test\Console;
 
 use Cake\Console\CommandCollection;
+use Cake\Console\CommandFactoryInterface;
 use Cake\Console\CommandRunner;
 use Cake\Console\ConsoleIo;
 use Cake\Console\Shell;
@@ -320,6 +321,31 @@ class CommandRunnerTest extends TestCase
     }
 
     /**
+     * Test using a custom factory
+     *
+     * @return void
+     */
+    public function testRunWithCustomFactory()
+    {
+        $output = new ConsoleOutput();
+        $io = $this->getMockIo($output);
+        $factory = $this->createMock(CommandFactoryInterface::class);
+        $factory->expects($this->once())
+            ->method('create')
+            ->with(DemoCommand::class, $io)
+            ->willReturn(new DemoCommand());
+
+        $app = $this->makeAppWithCommands(['ex' => DemoCommand::class]);
+
+        $runner = new CommandRunner($app, 'cake', $factory);
+        $result = $runner->run(['cake', 'ex'], $io);
+        $this->assertSame(Shell::CODE_SUCCESS, $result);
+
+        $messages = implode("\n", $output->messages());
+        $this->assertContains('Demo Command!', $messages);
+    }
+
+    /**
      * Test running a valid command
      *
      * @return void