8000 feature #3621 [Console] Command as service (gnugat) · symfony/symfony-docs@c75b1a7 · GitHub
[go: up one dir, main page]

Skip to content

Commit c75b1a7

Browse files
committed
feature #3621 [Console] Command as service (gnugat)
This PR was merged into the 2.4 branch. Discussion ---------- [Console] Command as service | Q | A | ------------- | --- | Doc fix? | yes | New docs? | no | Applies to | 2.4+ | Fixed tickets | N/A Command as a service can be useful to give access to services and configuration parameters in the `configure` method. A simple use case: you want to allow the user to set an option's default value in the `app/config/parameters.yml` file. Or the default value needs to be computed by a service (database retrieval for instance). With a `ContainerAwareCommand`, this wouldn't be possible because the `configure` method is called from the constructor, so the container isn't set yet. Original PR: #3620 Commits ------- c8fe610 Moved back and listened to @weaverryan e8b3320 Took into account @cordoval's feedback 11bfe50 Added warning about performances 6a7a25f Fixed @wouterj's feedback e137951 Created a new article cdd534a Added @lsmith77 and @dbu use cases a7b916e Fixed typos spotted by @cordoval a055140 Took @wouterj's advices into account 947ad92 [Console] Adding use cases to command as service
2 parents d8182fc + c8fe610 commit c75b1a7

File tree

3 files changed

+127
-48
lines changed

3 files changed

+127
-48
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
.. index::
2+
single: Console; Commands as Services
3+
4+
How to Define Commands as Services
5+
==================================
6+
7+
.. versionadded:: 2.4
8+
Support for registering commands in the service container was introduced in
9+
version 2.4.
10+
11+
By default, Symfony will take a look in the ``Command`` directory of each
12+
bundle and automatically register your commands. If a command extends the
13+
:class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`,
14+
Symfony will even inject the container.
15+
While making life easier, this has some limitations:
16+
17+
* Your command must live in the ``Command`` directory;
18+
* There's no way to conditionally register your service based on the environment
19+
or availability of some dependencies;
20+
* You can't access the container in the ``configure()`` method (because
21+
``setContainer`` hasn't been called yet);
22+
* You can't use the same class to create many commands (i.e. each with
23+
different configuration).
24+
25+
To solve these problems, you can register your command as a service and tag it
26+
with ``console.command``:
27+
28+
.. configuration-block::
29+
30+
.. code-block:: yaml
31+
32+
# app/config/config.yml
33+
services:
34+
acme_hello.command.my_command:
35+
class: Acme\HelloBundle\Command\MyCommand
36+
tags:
37+
- { name: console.command }
38+
39+
.. code-block:: xml
40+
41+
<!-- app/config/config.xml -->
42+
<?xml version="1.0" encoding="UTF-8" ?>
43+
<container xmlns="http://symfony.com/schema/dic/services"
44+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
45+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
46+
47+
<services>
48+
<service id="acme_hello.command.my_command"
49+
class="Acme\HelloBundle\Command\MyCommand">
50+
<tag name="console.command" />
51+
</service>
52+
</services>
53+
</container>
54+
55+
.. code-block:: php
56+
57+
// app/config/config.php
58+
$container
59+
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
60+
->addTag('console.command')
61+
;
62+
63+
Using Dependencies and Parameters to Set Default Values for Options
64+
-------------------------------------------------------------------
65+
66+
Imagine you want to provide a default value for the ``name`` option. You could
67+
pass one of the following as the 5th argument of ``addOption()``:
68+
69+
* a hardcoded string;
70+
* a container parameter (e.g. something from parameters.yml);
71+
* a value computed by a service (e.g. a repository).
72+
73+
By extending ``ContainerAwareCommand``, only the first is possible, because you
74+
can't access the container inside the ``configure()`` method. Instead, inject
75+
any parameter or service you need into the constructor. For example, suppose you
76+
have some ``NameRepository`` service that you'll use to get your default value::
77+
78+
// src/Acme/DemoBundle/Command/GreetCommand.php
79+
namespace Acme\DemoBundle\Command;
80+
81+
use Acme\DemoBundle\Entity\NameRepository;
82+
use Symfony\Component\Console\Command\Command;
83+
use Symfony\Component\Console\Input\InputInterface;
84+
use Symfony\Component\Console\Input\InputOption;
85+
use Symfony\Component\Console\Output\OutputInterface;
86+
87+
class GreetCommand extends Command
88+
{
89+
protected $nameRepository;
90+
91+
public function __construct(NameRepository $nameRepository)
92+
{
93+
$this->nameRepository = $nameRepository;
94+
}
95+
96+
protected function configure()
97+
{
98+
$defaultName = $this->nameRepository->findLastOne();
99+
100+
$this
101+
->setName('demo:greet')
102+
->setDescription('Greet someone')
103+
->addOption('name', '-n', InputOption::VALUE_REQUIRED, 'Who do you want to greet?', $defaultName)
104+
;
105+
}
106+
107+
protected function execute(InputInterface $input, OutputInterface $output)
108+
{
109+
$name = $input->getOption('name');
110+
111+
$output->writeln($name);
112+
}
113+
}
114+
115+
Now, just update the arguments of your service configuration like normal to
116+
inject the ``NameRepository``. Great, you now have a dynamic default value!
117+
118+
.. caution::
119+
120+
Be careful not to actually do any work in ``configure`` (e.g. make database
121+
queries), as your code will be run, even if you're using the console to
122+
execute a different command.

cookbook/console/console_command.rst

Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -65,55 +65,11 @@ This command will now automatically be available to run:
6565
.. _cookbook-console-dic:
6666

6767
Register Commands in the Service Container
68-
------------------------------------------
69-
70-
.. versionadded:: 2.4
71-
Support for registering commands in the service container was added in
72-
version 2.4.
73-
74-
Instead of putting your command in the ``Command`` directory and having Symfony
75-
auto-discover it for you, you can register commands in the service container
76-
using the ``console.command`` tag:
77-
78-
.. configuration-block::
79-
80-
.. code-block:: yaml
81-
82-
# app/config/config.yml
83-
services:
84-
acme_hello.command.my_command:
85-
class: Acme\HelloBundle\Command\MyCommand
86-
tags:
87-
- { name: console.command }
88-
89-
.. code-block:: xml
90-
91-
<!-- app/config/config.xml -->
92-
<?xml version="1.0" encoding="UTF-8" ?>
93-
<container xmlns="http://symfony.com/schema/dic/services"
94-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
95-
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
96-
97-
<service id="acme_hello.command.my_command"
98-
class="Acme\HelloBundle\Command\MyCommand">
99-
<tag name="console.command" />
100-
</service>
101-
</container>
102-
103-
.. code-block:: php
104-
105-
// app/config/config.php
106-
107-
$container
108-
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
109-
->addTag('console.command')
110-
;
111-
112-
.. tip::
68+
-------------------------------------------
11369

114-
Registering your command as a service gives you more control over its
115-
location and the services that are injected into it. But, there are no
116-
functional advantages, so you don't need to register your command as a service.
70+
Just like controllers, commands can be declared as services. See the
71+
:doc:`dedicated cookbook entry </cookbook/console/commands_as_services>`
72+
for details.
11773

11874
Getting Services from the Service Container
11975
-------------------------------------------

cookbook/console/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ Console
88
usage
99
sending_emails
1010
logging
11+
commands_as_services

0 commit comments

Comments
 (0)
0