|
1 |
| -Console |
2 |
| -======= |
| 1 | +.. index:: |
| 2 | + single: Console; Create commands |
3 | 3 |
|
4 |
| -.. toctree:: |
5 |
| - :maxdepth: 1 |
6 |
| - :glob: |
| 4 | +Console Commands |
| 5 | +================ |
7 | 6 |
|
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