Skip to content

Commit e137951

Browse files
author
Loïc Chardonnet
committed
Created a new article
1 parent cdd534a commit e137951

File tree

3 files changed

+119
-74
lines changed

3 files changed

+119
-74
lines changed
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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 added in
9+
version 2.4.
10+
11+
By default, Symfony will take a look in the ``Command`` directory of your
12+
bundles and automatically register your commands. For the ones implementing
13+
the ``ContainerAwareCommand`` interface, Symfony will even inject the container.
14+
15+
While making life easier, this default implementation has some drawbacks in some
16+
situations:
17+
18+
* what if you want your command to be defined elsewhere than in the ``Command``
19+
folder?
20+
* what if you want to register conditionally your command, depending on the
21+
current environment or on the availability of some dependencies?
22+
* what if you need to access dependencies before the ``setContainer`` is called
23+
(for example in the ``configure`` method)?
24+
* what if you want to reuse a command many times, but with different
25+
dependencies or parameters?
26+
27+
To solve those problems, you can register your command as a service by simply
28+
defining it with the ``console.command`` tag:
29+
30+
.. configuration-block::
31+
32+
.. code-block:: yaml
33+
34+
# app/config/config.yml
35+
services:
36+
acme_hello.command.my_command:
37+
class: Acme\HelloBundle\Command\MyCommand
38+
tags:
39+
- { name: console.command }
40+
41+
.. code-block:: xml
42+
43+
<!-- app/config/config.xml -->
44+
<?xml version="1.0" encoding="UTF-8" ?>
45+
<container xmlns="http://symfony.com/schema/dic/services"
46+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
47+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
48+
49+
<service id="acme_hello.command.my_command"
50+
class="Acme\HelloBundle\Command\MyCommand">
51+
<tag name="console.command" />
52+
</service>
53+
</container>
54+
55+
.. code-block:: php
56+
57+
// app/config/config.php
58+
59+
$container
60+
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
61+
->addTag('console.command')
62+
;
63+
64+
Here are some use cases.
65+
66+
Use dependencies and parameters in configure
67+
--------------------------------------------
68+
69+
For example, imagine you want to provide a default value for the ``name``
70+
argument. You could:
71+
72+
* hard code a string and pass it as the 4th argument of ``addArgument``;
73+
* allow the user to set the default value in the configuration;
74+
* retrieve the default value from a service (a repository for example).
75+
76+
With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the
77+
configuration parameter, because the ``configure`` method is called in the
78+
command's constructor. The only solution is to inject them through its
79+
constructor:
80+
81+
<?php
82+
// src/Acme/DemoBundle/Command/GreetCommand.php
83+
namespace Acme\DemoBundle\Command;
84+
85+
use Acme\DemoBundle\Entity\NameRepository;
86+
use Symfony\Component\Console\Command\Command;
87+
use Symfony\Component\Console\Input\InputArgument;
88+
use Symfony\Component\Console\Input\InputInterface;
89+
use Symfony\Component\Console\Input\InputOption;
90+
use Symfony\Component\Console\Output\OutputInterface;
91+
92+
class GreetCommand extends Command
93+
{
94+
protected $nameRepository;
95+
96+
public function __construct(NameRepository $nameRepository)
97+
{
98+
$this->nameRepository = $nameRepository;
99+
}
100+
101+
protected function configure()
102+
{
103+
$defaultName = $this->nameRepository->findLastOne();
104+
105+
$this
106+
->setName('demo:greet')
107+
->setDescription('Greet someone')
108+
->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?', $defaultName)
109+
;
110+
}
111+
112+
protected function execute(InputInterface $input, OutputInterface $output)
113+
{
114+
$name = $input->getArgument('name');
115+
116+
$output->writeln($name);
117+
}
118+
}

components/console/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Console
66

77
introduction
88
usage
9+
commands_as_services
910
single_command_tool
1011
events
1112
helpers/index

cookbook/console/console_command.rst

-74
Original file line numberDiff line numberDiff line change
@@ -62,80 +62,6 @@ This command will now automatically be available to run:
6262
6363
$ app/console demo:greet Fabien
6464
65-
.. _cookbook-console-dic:
66-
67-
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-
By default, Symfony will take a look in the ``Command`` directory of your
75-
bundles and automatically register your commands. For the ones implementing
76-
the ``ContainerAwareCommand`` interface, Symfony will even inject the container.
77-
78-
If you want to, you can instead register them as services in the container using
79-
the ``console.command`` tag:
80-
81-
.. configuration-block::
82-
83-
.. code-block:: yaml
84-
85-
# app/config/config.yml
86-
services:
87-
acme_hello.command.my_command:
88-
class: Acme\HelloBundle\Command\MyCommand
89-
tags:
90-
- { name: console.command }
91-
92-
.. code-block:: xml
93-
94-
<!-- app/config/config.xml -->
95-
<?xml version="1.0" encoding="UTF-8" ?>
96-
<container xmlns="http://symfony.com/schema/dic/services"
97-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
98-
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
99-
100-
<service id="acme_hello.command.my_command"
101-
class="Acme\HelloBundle\Command\MyCommand">
102-
<tag name="console.command" />
103-
</service>
104-
</container>
105-
106-
.. code-block:: php
107-
108-
// app/config/config.php
109-
110-
$container
111-
->register('acme_hello.command.my_command', 'Acme\HelloBundle\Command\MyCommand')
112-
->addTag('console.command')
113-
;
114-
115-
.. tip::
116-
117-
Commands as services can be useful in few situations:
118-
119-
* if you need your commands to be defined somewhere else than in the
120-
``Command`` folder;
121-
* if you need to register the command conditionally (depending on the
122-
environment or presence of some dependencies);
123-
* ou want to reuse the command with a different service or different
124-
configuration, without having to extend the command - you could just
125-
define a second service with the same class;
126-
* if you need to access services or configuration parameters in the
127-
``configure`` method.
128-
129-
For example, imagine you want to provide a default value for the ``name``
130-
option. You could hard code a string and pass it as the 4th argument of
131-
``addArgument``, or you could allow the user to set the default value in the
132-
configuration.
133-
134-
With a ``ContainerAwareCommand`` you wouldn't be able to retrieve the
135-
configuration parameter, because the ``configure`` method is called in the
136-
command's constructor. The only solution is to inject them through its
137-
constructor.
138-
13965
Getting Services from the Service Container
14066
-------------------------------------------
14167

0 commit comments

Comments
 (0)