-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[Console] Command as service #3621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
947ad92
a055140
a7b916e
cdd534a
e137951
6a7a25f
11bfe50
e8b3320
c8fe610
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
.. index:: | ||
single: Console; Commands as Services | ||
|
||
How to Define Commands as Services | ||
================================== | ||
|
||
.. versionadded:: 2.4 | ||
Support for registering commands in the service container was introduced in | ||
version 2.4. | ||
|
||
By default, Symfony will take a look in the ``Command`` directory of your | ||
bundles and automatically register your commands. For the ones implementing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have to be careful because we're talking about the
|
||
the ``ContainerAwareCommand`` interface, Symfony will even inject the container. | ||
While making life easier, this default implementation has some drawbacks in some | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest adding this to the previous paragraph |
||
situations: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... this has some limitations ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I rephrased each bullet point below so that they all sound like limitations (not things that you will be able to do after registering as as service), since we mention limitations/drawbacks here. |
||
|
||
* Define the command elsewhere than in the ``Command`` directory; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
* Conditionally register your command, depending on the current environment or | ||
on the availability of some dependencies; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
* Access dependencies before the ``setContainer()`` is called (for example in | ||
the ``configure()`` method); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
* Reuse a command many times, but with different dependencies or parameters | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
To solve those problems, you can register your command as a service by simply | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
defining it with the ``console.command`` tag: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In these cases we tag ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. -1 never use the first person |
||
|
||
.. configuration-block:: | ||
|
||
.. code-block:: yaml | ||
|
||
# app/config/config.yml | ||
services: | ||
acme_hello.command.my_command: | ||
class: Acme\HelloBundle\Command\MyCommand | ||
tags: | ||
- { name: console.command } | ||
|
||
.. code-block:: xml | ||
|
||
<!-- app/config/config.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 http://symfony.com/schema/dic/services/services-1.0.xsd"> | ||
|
||
<services> | ||
<service id="acme_hello.command.my_command" | ||
class="Acme\HelloBundle\Command\MyCommand"> | ||
<tag name="console.command" /> | ||
</service> | ||
</services> | ||
</container> | ||
|
||
.. code-block:: php | ||
|
||
// app/config/config.php | ||
$container | ||
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand') | ||
->addTag('console.command') | ||
; | ||
|
||
Using Dependencies and Parameters to Set Default Values for Options | ||
------------------------------------------------------------------- | ||
|
||
Imagine you want to provide a default value for the ``name``option. You could | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing a space between "name" and "option" |
||
pass one of the following as the 5th argument of ``addOption()``: | ||
|
||
* an hardcoded string; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
* a value coming from the configuration (allows the user to change it easily); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear that we're really talking about a dependency injection parameter, so I propose:
|
||
* a value computed by a service (e.g. a repository). | ||
|
||
With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
configuration parameter, because the ``configure()`` method is called in the | ||
constructor. The only solution is to inject them:: | ||
|
||
// src/Acme/DemoBundle/Command/GreetCommand.php | ||
namespace Acme\DemoBundle\Command; | ||
|
||
use Acme\DemoBundle\Entity\NameRepository; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Input\InputOption; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
|
||
class GreetCommand extends Command | ||
{ | ||
protected $nameRepository; | ||
|
||
public function __construct(NameRepository $nameRepository) | ||
{ | ||
$this->nameRepository = $nameRepository; | ||
} | ||
|
||
protected function configure() | ||
{ | ||
$defaultName = $this->nameRepository->findLastOne(); | ||
|
||
$this | ||
->setName('demo:greet') | ||
->setDescription('Greet someone') | ||
->addOption('name', '-n', InputOption::VALUE_REQUIRED, 'Who do you want to greet?', $defaultName) | ||
; | ||
} | ||
|
||
protected function execute(InputInterface $input, OutputInterface $output) | ||
{ | ||
$name = $input->getOption('name'); | ||
|
||
$output->writeln($name); | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now, just update the arguments of your service configuration like normal to inject the |
||
.. caution:: | ||
|
||
When running the console, every command is instantiated, which means every | ||
``configure()`` method is called. Be careful with database queries, as | ||
they could impact performance. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Be careful not to actually do any work in |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ Console | |
|
||
introduction | ||
usage | ||
commands_as_services | ||
single_command_tool | ||
events | ||
helpers/index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... of each bundle ...