How to Create a Console Command
Edit this pageWarning: You are browsing the documentation for Symfony 2.3, which is no longer maintained.
Read the updated version of this page for Symfony 6.3 (the current stable version).
How to Create a Console Command
The Console page of the Components section (The Console Component) covers how to create a console command. This cookbook article covers the differences when creating console commands within the Symfony Framework.
Automatically Registering Commands
To make the console commands available automatically with Symfony, create a
Command
directory inside your bundle and create a PHP file suffixed with
Command.php
for each command that you want to provide. For example, if you
want to extend the AppBundle to greet you from the command line, create
GreetCommand.php
and add the following to it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// src/AppBundle/Command/GreetCommand.php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class GreetCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('demo:greet')
->setDescription('Greet someone')
->addArgument(
'name',
InputArgument::OPTIONAL,
'Who do you want to greet?'
)
->addOption(
'yell',
null,
InputOption::VALUE_NONE,
'If set, the task will yell in uppercase letters'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
if ($name) {
$text = 'Hello '.$name;
} else {
$text = 'Hello';
}
if ($input->getOption('yell')) {
$text = strtoupper($text);
}
$output->writeln($text);
}
}
This command will now automatically be available to run:
1
$ php app/console demo:greet Fabien
Getting Services from the Service Container
By using ContainerAwareCommand as the base class for the command (instead of the more basic Command), you have access to the service container. In other words, you have access to any configured service:
1 2 3 4 5 6 7 8
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$logger = $this->getContainer()->get('logger');
$logger->info('Executing command for '.$name);
// ...
}
However, due to the container scopes this
code doesn't work for some services. For instance, if you try to get the request
service or any other service related to it, you'll get the following error:
1
You cannot create a service ("request") of an inactive scope ("request").
Consider the following example that uses the translator
service to
translate some contents using a console command:
1 2 3 4 5 6 7 8 9 10 11 12
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$translator = $this->getContainer()->get('translator');
if ($name) {
$output->writeln(
$translator->trans('Hello %name%!', array('%name%' => $name))
);
} else {
$output->writeln($translator->trans('Hello!'));
}
}
If you dig into the Translator component classes, you'll see that the request
service is required to get the locale into which the contents are translated:
1 2 3 4 5 6 7 8 9 10
// vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php
public function getLocale()
{
if (null === $this->locale && $this->container->isScopeActive('request')
&& $this->container->has('request')) {
$this->locale = $this->container->get('request')->getLocale();
}
return $this->locale;
}
Therefore, when using the translator
service inside a command, you'll get the
previous "You cannot create a service of an inactive scope" error message.
The solution in this case is as easy as setting the locale value explicitly
before translating contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
protected function execute(InputInterface $input, OutputInterface $output)
{
$name = $input->getArgument('name');
$locale = $input->getArgument('locale');
$translator = $this->getContainer()->get('translator');
$translator->setLocale($locale);
if ($name) {
$output->writeln(
$translator->trans('Hello %name%!', array('%name%' => $name))
);
} else {
$output->writeln($translator->trans('Hello!'));
}
}
However, for other services the solution might be more complex. For more details, see How to Work with Scopes.
Invoking other Commands
See The Console Component if you need to implement a command that runs other dependent commands.
Testing Commands
When testing commands used as part of the full-stack framework, Symfony\\Bundle\\FrameworkBundle\\Console\\Application should be used instead of Symfony\\Component\\Console\\Application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use AppBundle\Command\GreetCommand;
class ListCommandTest extends \PHPUnit_Framework_TestCase
{
public function testExecute()
{
// mock the Kernel or create one depending on your needs
$application = new Application($kernel);
$application->add(new GreetCommand());
$command = $application->find('demo:greet');
$commandTester = new CommandTester($command);
$commandTester->execute(
array(
'command' => $command->getName(),
'name' => 'Fabien',
'--yell' => true,
)
);
$this->assertRegExp('/.../', $commandTester->getDisplay());
// ...
}
}
Note
In the specific case above, the name
parameter and the --yell
option
are not mandatory for the command to work, but are shown so you can see
how to customize them when calling the command.
To be able to use the fully set up service container for your console tests you can extend your test from WebTestCase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use AppBundle\Command\GreetCommand;
class ListCommandTest extends WebTestCase
{
public function testExecute()
{
$kernel = $this->createKernel();
$kernel->boot();
$application = new Application($kernel);
$application->add(new GreetCommand());
$command = $application->find('demo:greet');
$commandTester = new CommandTester($command);
$commandTester->execute(
array(
'command' => $command->getName(),
'name' => 'Fabien',
'--yell' => true,
)
);
$this->assertRegExp('/.../', $commandTester->getDisplay());
// ...
}
}