Skip to content

Commit cbca1c0

Browse files
committed
Rewrote Console Commands introduction
1 parent 2d355f3 commit cbca1c0

File tree

2 files changed

+278
-184
lines changed

2 files changed

+278
-184
lines changed

console.rst

Lines changed: 278 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,280 @@
1-
Console
2-
=======
1+
.. index::
2+
single: Console; Create commands
33

4-
.. toctree::
5-
:maxdepth: 1
6-
:glob:
4+
Console Commands
5+
================
76

8-
console/*
7+
The Symfony framework provide lots of commands through the ``app/console`` file
8+
(e.g. the common ``app/console cache:clear`` command). These commands are
9+
created using the :doc:`Console component </components/console>`. This allows
10+
you to add custom commands as well, for instance to manage admin users.
11+
12+
Creating a Command
13+
------------------
14+
15+
Each command will have its own command class that manages the logic. It serves
16+
as a controller for the console, except that it doesn't work with the HTTP
17+
Request/Response flow, but with Input/Output streams.
18+
19+
Your command has to be in the ``Command`` namespace of your bundle (e.g.
20+
``AppBundle\Command``) and the name has to end with ``Command``.
21+
22+
For instance, assume you create a command to generate new admin users (you'll
23+
learn about the methods soon)::
24+
25+
// src/AppBundle/Command/GenerateAdminCommand.php
26+
namespace AppBundle\Command;
27+
28+
use Symfony\Component\Console\Command\Command;
29+
use Symfony\Component\Console\Input\InputInterface;
30+
use Symfony\Component\Console\Output\OutputInterface;
31+
32+
class GenerateAdminCommand extends Command
33+
{
34+
protected function configure()
35+
{
36+
// ...
37+
}
38+
39+
protected function execute(InputInterface $input, OutputInterface $output)
40+
{
41+
// ...
42+
}
43+
}
44+
45+
Configuring the Command
46+
-----------------------
47+
48+
First of all, you need to configure the name of the command in ``configure()``.
49+
Besides the name, you can configure things like the help message and
50+
:doc:`input options and arguments </console/input>`.
51+
52+
::
53+
54+
// ...
55+
protected function configure()
56+
{
57+
$this
58+
// the name of the command (the part after "app/console")
59+
->setName('app:generate-admin')
60+
61+
// the shot description shown while running "php app/console list"
62+
->setDescription('Generates new admin users.')
63+
64+
// the help message shown when running the command with the
65+
// "--help" option
66+
->setHelp(<<<EOT
67+
This command allows you to generate admins.
68+
69+
...
70+
EOT
71+
)
72+
;
73+
}
74+
75+
Executing the Command
76+
---------------------
77+
78+
After configuring, you can execute the command in the terminal:
79+
80+
.. code-block:: bash
81+
82+
$ php app/console app:generate-admin
83+
84+
As you might expect, this command will do nothing as you didn't write any logic
85+
yet. When running the command, the ``execute()`` method will be executed. This
86+
method has access to the input stream (e.g. options and arguments) and the
87+
output stream (to write messages to the console)::
88+
89+
// ...
90+
protected function execute(InputInterface $input, OutputInterface $output)
91+
{
92+
// outputs multiple lines to the console
93+
$output->writeln([
94+
'Admin Generator',
95+
'===============',
96+
'',
97+
]);
98+
99+
// output a single line
100+
$output->writeln('Whoa!');
101+
102+
// output a message without moving to a new line (the message will
103+
// apear on one line)
104+
$output->write('You\'re about to');
105+
$output->write('generate an admin user.');
106+
}
107+
108+
Now, try executing the command:
109+
110+
.. code-block:: bash
111+
112+
$ php app/console app:generate-admin
113+
Admin Generator
114+
===============
115+
116+
Whoa!
117+
You're about to generate an admin user.
118+
119+
Console Input
120+
-------------
121+
122+
Use input options or arguments to pass information to the command::
123+
124+
use Symfony\Component\Console\Input\InputArgument;
125+
126+
// ...
127+
protected function configure()
128+
{
129+
$this
130+
// configure an argument
131+
->addArgument('username', InputArgument::REQUIRED, 'The username of the admin.')
132+
// ...
133+
;
134+
}
135+
136+
// ...
137+
public function execute(InputInterface $input, OutputInterface $output)
138+
{
139+
$output->writeln([
140+
'Admin Generator',
141+
'===============',
142+
'',
143+
]);
144+
145+
// retrieve the argument value using getArgument()
146+
$this->writeln('Username: '.$input->getArgument('username'));
147+
}
148+
149+
Now, you can pass the username to the command:
150+
151+
.. code-block:: bash
152+
153+
$ php app/console app:generate-admin Wouter
154+
Admin Generator
155+
===============
156+
157+
Username: Wouter
158+
159+
.. seealso::
160+
161+
Read :doc:`/console/input` for more information about console options and
162+
arguments.
163+
164+
Getting Services from the Service Container
165+
-------------------------------------------
166+
167+
To actually generate a new admin user, the command has to access some
168+
:doc:`services </service_container>`. This can be done by extending
169+
:class:`Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand`
170+
instead::
171+
172+
// ...
173+
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
174+
175+
class GenerateAdminCommand extends ContainerAwareCommand
176+
{
177+
// ...
178+
179+
protected function execute(InputInterface $input, OutputInterface $output)
180+
{
181+
// ...
182+
183+
// access the container using getContainer()
184+
$adminGenerator = $this->getContainer()->get('app.admin_generator');
185+
186+
$generatedPassword = md5(uniqid());
187+
188+
$output->writeln('Generated password: '.$generatedPassword);
189+
190+
// for instance, generate an admin like this
191+
$adminGenerator->generate($input->getArgument('username'), $generatedPassword);
192+
193+
$output->writeln('Admin successfully generated!');
194+
}
195+
}
196+
197+
Now, once you created the required services and logic, the command will execute
198+
the ``generate()`` method of the ``app.admin_generator`` service and the admin
199+
will be created.
200+
201+
Invoking other Commands
202+
-----------------------
203+
204+
See :ref:`calling-existing-command` if you need to implement a command that runs
205+
other dependent commands.
206+
207+
Testing Commands
208+
----------------
209+
210+
When testing commands used as part of the full-stack framework,
211+
:class:`Symfony\\Bundle\\FrameworkBundle\\Console\\Application <Symfony\\Bundle\\FrameworkBundle\\Console\\Application>`
212+
should be used instead of
213+
:class:`Symfony\\Component\\Console\\Application <Symfony\\Component\\Console\\Application>`::
214+
215+
use Symfony\Component\Console\Tester\CommandTester;
216+
use Symfony\Bundle\FrameworkBundle\Console\Application;
217+
use AppBundle\Command\GreetCommand;
218+
219+
class ListCommandTest extends \PHPUnit_Framework_TestCase
220+
{
221+
public function testExecute()
222+
{
223+
// mock the Kernel or create one depending on your needs
224+
$application = new Application($kernel);
225+
$application->add(new GreetCommand());
226+
227+
$command = $application->find('demo:greet');
228+
$commandTester = new CommandTester($command);
229+
$commandTester->execute(
230+
array(
231+
'name' => 'Fabien',
232+
'--yell' => true,
233+
)
234+
);
235+
236+
$this->assertRegExp('/.../', $commandTester->getDisplay());
237+
238+
// ...
239+
}
240+
}
241+
242+
.. note::
243+
244+
In the specific case above, the ``name`` parameter and the ``--yell`` option
245+
are not mandatory for the command to work, but are shown so you can see
246+
how to customize them when calling the command.
247+
248+
To be able to use the fully set up service container for your console tests
249+
you can extend your test from
250+
:class:`Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase`::
251+
252+
use Symfony\Component\Console\Tester\CommandTester;
253+
use Symfony\Bundle\FrameworkBundle\Console\Application;
254+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
255+
use AppBundle\Command\GreetCommand;
256+
257+
class ListCommandTest extends KernelTestCase
258+
{
259+
public function testExecute()
260+
{
261+
$kernel = $this->createKernel();
262+
$kernel->boot();
263+
264+
$application = new Application($kernel);
265+
$application->add(new GreetCommand());
266+
267+
$command = $application->find('demo:greet');
268+
$commandTester = new CommandTester($command);
269+
$commandTester->execute(
270+
array(
271+
'name' => 'Fabien',
272+
'--yell' => true,
273+
)
274+
);
275+
276+
$this->assertRegExp('/.../', $commandTester->getDisplay());
277+
278+
// ...
279+
}
280+
}

0 commit comments

Comments
 (0)