Browse files

[FrameworkBundle] Adds the possibility to register Commands via the DIC

  • Loading branch information...
1 parent 678e1de commit cabb1fa8bb60948fe38afd37ddf70d854aae9f5a @lyrixx lyrixx committed with fabpot Sep 6, 2013
View
8 src/Symfony/Bundle/FrameworkBundle/Console/Application.php
@@ -98,6 +98,14 @@ public function doRun(InputInterface $input, OutputInterface $output)
protected function registerCommands()
{
+ $container = $this->kernel->getContainer();
+
+ if ($container->hasParameter('console.command.ids')) {
+ foreach ($container->getParameter('console.command.ids') as $id) {
+ $this->add($container->get($id));
+ }
+ }
+
foreach ($this->kernel->getBundles() as $bundle) {
if ($bundle instanceof Bundle) {
$bundle->registerCommands($this);
View
49 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddConsoleCommandPass.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * AddConsoleCommandPass.
+ *
+ * @author Grégoire Pineau <lyrixx@lyrixx.info>
+ */
+class AddConsoleCommandPass implements CompilerPassInterface
+{
+ public function process(ContainerBuilder $container)
+ {
+ $commandServices = $container->findTaggedServiceIds('console.command');
+
+ foreach ($commandServices as $id => $tags) {
+ $definition = $container->getDefinition($id);
+
+ if (!$definition->isPublic()) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must be public.', $id));
+ }
+
+ if ($definition->isAbstract()) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must not be abstract.', $id));
+ }
+
+ $class = $container->getParameterBag()->resolveValue($definition->getClass());
+ $r = new \ReflectionClass($class);
+ if (!$r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command')) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" tagged "console.command" must be a subclass of "Symfony\\Component\\Console\\Command\\Command".', $id));
+ }
+ $container->setAlias('console.command.'.strtolower(str_replace('\\', '_', $class)), $id);
+ }
+
+ $container->setParameter('console.command.ids', array_keys($commandServices));
+ }
+}
View
2 src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -13,6 +13,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass;
+use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass;
@@ -71,6 +72,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new TemplatingPass());
$container->addCompilerPass(new AddConstraintValidatorsPass());
$container->addCompilerPass(new AddValidatorInitializersPass());
+ $container->addCompilerPass(new AddConsoleCommandPass());
$container->addCompilerPass(new FormPass());
$container->addCompilerPass(new TranslatorPass());
$container->addCompilerPass(new AddCacheWarmerPass());
View
12 src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php
@@ -74,6 +74,18 @@ private function getKernel(array $bundles)
->with($this->equalTo('event_dispatcher'))
->will($this->returnValue($dispatcher))
;
+ $container
+ ->expects($this->once())
+ ->method('hasParameter')
+ ->with($this->equalTo('console.command.ids'))
+ ->will($this->returnValue(true))
+ ;
+ $container
+ ->expects($this->once())
+ ->method('getParameter')
+ ->with($this->equalTo('console.command.ids'))
+ ->will($this->returnValue(array()))
+ ;
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
$kernel
View
96 ...y/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddConsoleCommandPassTest.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
+
+use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+
+class AddConsoleCommandPassTest extends \PHPUnit_Framework_TestCase
+{
+ public function testProcess()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass());
+ $container->setParameter('my-command.class', 'Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\MyCommand');
+
+ $definition = new Definition('%my-command.class%');
+ $definition->addTag('console.command');
+ $container->setDefinition('my-command', $definition);
+
+ $container->compile();
+
+ $alias = 'console.command.symfony_bundle_frameworkbundle_tests_dependencyinjection_compiler_mycommand';
+ $this->assertTrue($container->hasAlias($alias));
+ $this->assertSame('my-command', (string) $container->getAlias($alias));
+
+ $this->assertTrue($container->hasParameter('console.command.ids'));
+ $this->assertSame(array('my-command'), $container->getParameter('console.command.ids'));
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage The service "my-command" tagged "console.command" must be public.
+ */
+ public function testProcessThrowAnExceptionIfTheServiceIsNotPublic()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass());
+
+ $definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\MyCommand');
+ $definition->addTag('console.command');
+ $definition->setPublic(false);
+ $container->setDefinition('my-command', $definition);
+
+ $container->compile();
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage The service "my-command" tagged "console.command" must not be abstract.
+ */
+ public function testProcessThrowAnExceptionIfTheServiceIsAbstract()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass());
+
+ $definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\MyCommand');
+ $definition->addTag('console.command');
+ $definition->setAbstract(true);
+ $container->setDefinition('my-command', $definition);
+
+ $container->compile();
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage The service "my-command" tagged "console.command" must be a subclass of "Symfony\Component\Console\Command\Command".
+ */
+ public function testProcessThrowAnExceptionIfTheServiceIsNotASubclassOfCommand()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass());
+
+ $definition = new Definition('SplObjectStorage');
+ $definition->addTag('console.command');
+ $container->setDefinition('my-command', $definition);
+
+ $container->compile();
+ }
+}
+
+class MyCommand extends Command
+{
+
+}
View
9 src/Symfony/Component/HttpKernel/Bundle/Bundle.php
@@ -187,7 +187,14 @@ public function registerCommands(Application $application)
if ($relativePath = $file->getRelativePath()) {
$ns .= '\\'.strtr($relativePath, '/', '\\');
}
- $r = new \ReflectionClass($ns.'\\'.$file->getBasename('.php'));
+ $class = $ns.'\\'.$file->getBasename('.php');
+ if ($this->container) {
+ $alias = 'console.command.'.strtolower(str_replace('\\', '_', $class));
+ if ($this->container->has($alias)) {
+ continue;
+ }
+ }
+ $r = new \ReflectionClass($class);
if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract() && !$r->getConstructor()->getNumberOfRequiredParameters()) {
$application->add($r->newInstance());
}
View
25 src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php
@@ -11,11 +11,13 @@
namespace Symfony\Component\HttpKernel\Tests\Bundle;
+use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\HttpKernel\Bundle\Bundle;
-
-use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\ExtensionPresentBundle;
use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionAbsentBundle\ExtensionAbsentBundle;
use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\Command\FooCommand;
+use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\ExtensionPresentBundle;
class BundleTest extends \PHPUnit_Framework_TestCase
{
@@ -31,6 +33,25 @@ public function testRegisterCommands()
$bundle2 = new ExtensionAbsentBundle();
$this->assertNull($bundle2->registerCommands($app));
+ }
+ public function testRegisterCommandsIngoreCommandAsAService()
+ {
+ $container = new ContainerBuilder();
+ $container->addCompilerPass(new AddConsoleCommandPass());
+ $definition = new Definition('Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\Command\FooCommand');
+ $definition->addTag('console.command');
+ $container->setDefinition('my-command', $definition);
+ $container->compile();
+
+ $application = $this->getMock('Symfony\Component\Console\Application');
+ // Never called, because it's the
+ // Symfony\Bundle\FrameworkBundle\Console\Application that register
+ // commands as a service
+ $application->expects($this->never())->method('add');
+
+ $bundle = new ExtensionPresentBundle();
+ $bundle->setContainer($container);
+ $bundle->registerCommands($application);
}
}

0 comments on commit cabb1fa

Please sign in to comment.