How to Define Commands as Services
Warning: You are browsing the documentation for Symfony 4.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
If you're using the default services.yaml configuration, your command classes are already registered as services. Great! This is the recommended setup.
Note
You can also manually register your command as a service by configuring the service
and tagging it with console.command
.
For example, suppose you want to log something from within your command:
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
namespace App\Command;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SunshineCommand extends Command
{
protected static $defaultName = 'app:sunshine';
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
// you *must* call the parent constructor
parent::__construct();
}
protected function configure(): void
{
$this
->setDescription('Good morning!');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->logger->info('Waking up the sun');
// ...
return 0;
}
}
If you're using the default services.yaml configuration,
the command class will automatically be registered as a service and passed the $logger
argument (thanks to autowiring). In other words, you only need to create this
class and everything works automatically! You can call the app:sunshine
command and start logging.
Caution
You do have access to services in configure()
. However, if your command is
not lazy, try to avoid doing any
work (e.g. making database queries), as that code will be run, even if you're using
the console to execute a different command.
Note
In previous Symfony versions, you could make the command class extend from
ContainerAwareCommand to
get services via $this->getContainer()->get('SERVICE_ID')
. This is
deprecated in Symfony 4.2 and it won't work in future Symfony versions.
Lazy Loading
To make your command lazily loaded, either define its $defaultName
static property:
1 2 3 4 5 6
class SunshineCommand extends Command
{
protected static $defaultName = 'app:sunshine';
// ...
}
Or set the command
attribute on the console.command
tag in your service definition:
1 2 3 4 5 6 7
# config/services.yaml
services:
# ...
App\Command\SunshineCommand:
tags:
- { name: 'console.command', command: 'app:sunshine' }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<!-- config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
https://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<!-- ... -->
<service id="App\Command\SunshineCommand">
<tag name="console.command" command="app:sunshine"/>
</service>
</services>
</container>
1 2 3 4 5 6 7
// config/services.php
use App\Command\SunshineCommand;
// ...
$container->register(SunshineCommand::class)
->addTag('console.command', ['command' => 'app:sunshine'])
;
Note
If the command defines aliases (using the
getAliases() method)
you must add one console.command
tag per alias.
That's it. One way or another, the SunshineCommand
will be instantiated
only when the app:sunshine
command is actually called.
Note
You don't need to call setName()
for configuring the command when it is lazy.
Caution
Calling the list
command will instantiate all commands, including lazy commands.