diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 542d00623b..b337ecf992 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -4,7 +4,8 @@ CHANGELOG 3.4.0 ----- - * added `CommandLoaderInterface` and PSR-11 `ContainerCommandLoader` + * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11 + `ContainerCommandLoader` for commands lazy-loading 3.3.0 ----- diff --git a/src/Symfony/Component/Console/CommandLoader/FactoryCommandLoader.php b/src/Symfony/Component/Console/CommandLoader/FactoryCommandLoader.php new file mode 100644 index 0000000000..d9c2055710 --- /dev/null +++ b/src/Symfony/Component/Console/CommandLoader/FactoryCommandLoader.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\CommandLoader; + +use Symfony\Component\Console\Exception\CommandNotFoundException; + +/** + * A simple command loader using factories to instantiate commands lazily. + * + * @author Maxime Steinhausser + */ +class FactoryCommandLoader implements CommandLoaderInterface +{ + private $factories; + + /** + * @param callable[] $factories Indexed by command names + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + */ + public function has($name) + { + return isset($this->factories[$name]); + } + + /** + * {@inheritdoc} + */ + public function get($name) + { + if (!isset($this->factories[$name])) { + throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + } + + $factory = $this->factories[$name]; + + return $factory(); + } + + /** + * {@inheritdoc} + */ + public function getNames() + { + return array_keys($this->factories); + } +} diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 7bf76ddc8e..d475f12bc9 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Console\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\CommandLoader\ContainerCommandLoader; +use Symfony\Component\Console\CommandLoader\FactoryCommandLoader; use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\FormatterHelper; @@ -35,7 +35,6 @@ use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\EventDispatcher\EventDispatcher; class ApplicationTest extends TestCase @@ -129,10 +128,9 @@ class ApplicationTest extends TestCase $commands = $application->all('foo'); $this->assertCount(1, $commands, '->all() takes a namespace as its first argument'); - $application->setCommandLoader(new ContainerCommandLoader( - new ServiceLocator(array('foo-bar' => function () { return new \Foo1Command(); })), - array('foo:bar1' => 'foo-bar') - )); + $application->setCommandLoader(new FactoryCommandLoader(array( + 'foo:bar1' => function () { return new \Foo1Command(); }, + ))); $commands = $application->all('foo'); $this->assertCount(2, $commands, '->all() takes a namespace as its first argument'); $this->assertInstanceOf(\FooCommand::class, $commands['foo:bar'], '->all() returns the registered commands'); @@ -202,9 +200,9 @@ class ApplicationTest extends TestCase $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns a command by name'); $this->assertEquals($foo, $application->get('afoobar'), '->get() returns a command by alias'); - $application->setCommandLoader(new ContainerCommandLoader(new ServiceLocator(array( - 'foo-bar' => function () { return new \Foo1Command(); }, - )), array('foo:bar1' => 'foo-bar', 'afoobar1' => 'foo-bar'))); + $application->setCommandLoader(new FactoryCommandLoader(array( + 'foo:bar1' => function () { return new \Foo1Command(); }, + ))); $this->assertTrue($application->has('afoobar'), '->has() returns true if an instance is registered for an alias even with command loader'); $this->assertEquals($foo, $application->get('foo:bar'), '->get() returns an instance by name even with command loader'); @@ -321,9 +319,9 @@ class ApplicationTest extends TestCase public function testFindWithCommandLoader() { $application = new Application(); - $application->setCommandLoader(new ContainerCommandLoader(new ServiceLocator(array( - 'foo-bar' => $f = function () { return new \FooCommand(); }, - )), array('foo:bar' => 'foo-bar'))); + $application->setCommandLoader(new FactoryCommandLoader(array( + 'foo:bar' => $f = function () { return new \FooCommand(); }, + ))); $this->assertInstanceOf('FooCommand', $application->find('foo:bar'), '->find() returns a command if its name exists'); $this->assertInstanceOf('Symfony\Component\Console\Command\HelpCommand', $application->find('h'), '->find() returns a command if its name exists'); diff --git a/src/Symfony/Component/Console/Tests/CommandLoader/FactoryCommandLoaderTest.php b/src/Symfony/Component/Console/Tests/CommandLoader/FactoryCommandLoaderTest.php new file mode 100644 index 0000000000..5ee6cd1ec3 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/CommandLoader/FactoryCommandLoaderTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\CommandLoader; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\CommandLoader\FactoryCommandLoader; + +class FactoryCommandLoaderTest extends TestCase +{ + public function testHas() + { + $loader = new FactoryCommandLoader(array( + 'foo' => function () { return new Command('foo'); }, + 'bar' => function () { return new Command('bar'); }, + )); + + $this->assertTrue($loader->has('foo')); + $this->assertTrue($loader->has('bar')); + $this->assertFalse($loader->has('baz')); + } + + public function testGet() + { + $loader = new FactoryCommandLoader(array( + 'foo' => function () { return new Command('foo'); }, + 'bar' => function () { return new Command('bar'); }, + )); + + $this->assertInstanceOf(Command::class, $loader->get('foo')); + $this->assertInstanceOf(Command::class, $loader->get('bar')); + } + + /** + * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException + */ + public function testGetUnknownCommandThrows() + { + (new FactoryCommandLoader(array()))->get('unknown'); + } + + public function testGetCommandNames() + { + $loader = new FactoryCommandLoader(array( + 'foo' => function () { return new Command('foo'); }, + 'bar' => function () { return new Command('bar'); }, + )); + + $this->assertSame(array('foo', 'bar'), $loader->getNames()); + } +}