Console Commands

Console Commands

The Symfony framework provides lots of commands through the bin/console script (e.g. the well-known bin/console cache:clear command). These commands are created with the Console component. You can also use it to create your own commands.

The Console: APP_ENV & APP_DEBUG

Console commands run in the environment defined in the APP_ENV variable of the .env file, which is dev by default. It also reads the APP_DEBUG value to turn “debug” mode on or off (it defaults to 1, which is on).

To run the command in another environment or debug mode, edit the value of APP_ENV and APP_DEBUG.

Creating a Command

Commands are defined in classes extending Symfony\Component\Console\Command\Command. For example, you may want a command to create a user:

  1. // src/Command/CreateUserCommand.php
  2. namespace App\Command;
  3. use Symfony\Component\Console\Command\Command;
  4. use Symfony\Component\Console\Input\InputInterface;
  5. use Symfony\Component\Console\Output\OutputInterface;
  6. class CreateUserCommand extends Command
  7. {
  8. // the name of the command (the part after "bin/console")
  9. protected static $defaultName = 'app:create-user';
  10. protected function configure(): void
  11. {
  12. // ...
  13. }
  14. protected function execute(InputInterface $input, OutputInterface $output): int
  15. {
  16. // ... put here the code to create the user
  17. // this method must return an integer number with the "exit status code"
  18. // of the command. You can also use these constants to make code more readable
  19. // return this if there was no problem running the command
  20. // (it's equivalent to returning int(0))
  21. return Command::SUCCESS;
  22. // or return this if some error happened during the execution
  23. // (it's equivalent to returning int(1))
  24. // return Command::FAILURE;
  25. // or return this to indicate incorrect command usage; e.g. invalid options
  26. // or missing arguments (it's equivalent to returning int(2))
  27. // return Command::INVALID
  28. }
  29. }

New in version 5.1: The Command::SUCCESS and Command::FAILURE constants were introduced in Symfony 5.1.

New in version 5.3: The Command::INVALID constant was introduced in Symfony 5.3

Configuring the Command

You can optionally define a description, help message and the input options and arguments:

  1. // ...
  2. protected function configure(): void
  3. {
  4. $this
  5. // the short description shown while running "php bin/console list"
  6. ->setDescription('Creates a new user.')
  7. // the full command description shown when running the command with
  8. // the "--help" option
  9. ->setHelp('This command allows you to create a user...')
  10. ;
  11. }

The configure() method is called automatically at the end of the command constructor. If your command defines its own constructor, set the properties first and then call to the parent constructor, to make those properties available in theconfigure() method:

  1. // ...
  2. use Symfony\Component\Console\Command\Command;
  3. use Symfony\Component\Console\Input\InputArgument;
  4. class CreateUserCommand extends Command
  5. {
  6. // ...
  7. public function __construct(bool $requirePassword = false)
  8. {
  9. // best practices recommend to call the parent constructor first and
  10. // then set your own properties. That wouldn't work in this case
  11. // because configure() needs the properties set in this constructor
  12. $this->requirePassword = $requirePassword;
  13. parent::__construct();
  14. }
  15. protected function configure(): void
  16. {
  17. $this
  18. // ...
  19. ->addArgument('password', $this->requirePassword ? InputArgument::REQUIRED : InputArgument::OPTIONAL, 'User password')
  20. ;
  21. }
  22. }

Registering the Command

Symfony commands must be registered as services and tagged with the console.command tag. If you’re using the default services.yaml configuration, this is already done for you, thanks to autoconfiguration.

Executing the Command

After configuring and registering the command, you can run it in the terminal:

  1. $ php bin/console app:create-user

As you might expect, this command will do nothing as you didn’t write any logic yet. Add your own logic inside the `execute() method.

Console Output

The `execute() method has access to the output stream to write messages to the console:

  1. // ...
  2. protected function execute(InputInterface $input, OutputInterface $output): int
  3. {
  4. // outputs multiple lines to the console (adding "\n" at the end of each line)
  5. $output->writeln([
  6. 'User Creator',
  7. '============',
  8. '',
  9. ]);
  10. // the value returned by someMethod() can be an iterator (https://secure.php.net/iterator)
  11. // that generates and returns the messages with the 'yield' PHP keyword
  12. $output->writeln($this->someMethod());
  13. // outputs a message followed by a "\n"
  14. $output->writeln('Whoa!');
  15. // outputs a message without adding a "\n" at the end of the line
  16. $output->write('You are about to ');
  17. $output->write('create a user.');
  18. return Command::SUCCESS;
  19. }

Now, try executing the command:

  1. $ php bin/console app:create-user
  2. User Creator
  3. ============
  4. Whoa!
  5. You are about to create a user.

Output Sections

The regular console output can be divided into multiple independent regions called “output sections”. Create one or more of these sections when you need to clear and overwrite the output information.

Sections are created with the ConsoleOutput::section() method, which returns an instance of Symfony\Component\Console\Output\ConsoleSectionOutput:

  1. // ...
  2. use Symfony\Component\Console\Output\ConsoleOutputInterface;
  3. class MyCommand extends Command
  4. {
  5. protected function execute(InputInterface $input, OutputInterface $output): int
  6. {
  7. if (!$output instanceof ConsoleOutputInterface) {
  8. throw new \LogicException('This command accepts only an instance of "ConsoleOutputInterface".');
  9. }
  10. $section1 = $output->section();
  11. $section2 = $output->section();
  12. $section1->writeln('Hello');
  13. $section2->writeln('World!');
  14. // Output displays "Hello\nWorld!\n"
  15. // overwrite() replaces all the existing section contents with the given content
  16. $section1->overwrite('Goodbye');
  17. // Output now displays "Goodbye\nWorld!\n"
  18. // clear() deletes all the section contents...
  19. $section2->clear();
  20. // Output now displays "Goodbye\n"
  21. // ...but you can also delete a given number of lines
  22. // (this example deletes the last two lines of the section)
  23. $section1->clear(2);
  24. // Output is now completely empty!
  25. return Command::SUCCESS;
  26. }
  27. }

Note

A new line is appended automatically when displaying information in a section.

Output sections let you manipulate the Console output in advanced ways, such as displaying multiple progress bars which are updated independently and appending rows to tables that have already been rendered.

Console Input

Use input options or arguments to pass information to the command:

  1. use Symfony\Component\Console\Input\InputArgument;
  2. // ...
  3. protected function configure(): void
  4. {
  5. $this
  6. // configure an argument
  7. ->addArgument('username', InputArgument::REQUIRED, 'The username of the user.')
  8. // ...
  9. ;
  10. }
  11. // ...
  12. public function execute(InputInterface $input, OutputInterface $output): int
  13. {
  14. $output->writeln([
  15. 'User Creator',
  16. '============',
  17. '',
  18. ]);
  19. // retrieve the argument value using getArgument()
  20. $output->writeln('Username: '.$input->getArgument('username'));
  21. return Command::SUCCESS;
  22. }

Now, you can pass the username to the command:

  1. $ php bin/console app:create-user Wouter
  2. User Creator
  3. ============
  4. Username: Wouter

See also

Read Console Input (Arguments & Options) for more information about console options and arguments.

Getting Services from the Service Container

To actually create a new user, the command has to access some services. Since your command is already registered as a service, you can use normal dependency injection. Imagine you have a App\Service\UserManager service that you want to access:

  1. // ...
  2. use App\Service\UserManager;
  3. use Symfony\Component\Console\Command\Command;
  4. class CreateUserCommand extends Command
  5. {
  6. private $userManager;
  7. public function __construct(UserManager $userManager)
  8. {
  9. $this->userManager = $userManager;
  10. parent::__construct();
  11. }
  12. // ...
  13. protected function execute(InputInterface $input, OutputInterface $output): int
  14. {
  15. // ...
  16. $this->userManager->create($input->getArgument('username'));
  17. $output->writeln('User successfully generated!');
  18. return Command::SUCCESS;
  19. }
  20. }

Command Lifecycle

Commands have three lifecycle methods that are invoked when running the command:

initialize() (optional)

This method is executed before the interact() and theexecute() methods. Its main purpose is to initialize variables used in the rest of the command methods.

interact() (optional)

This method is executed after initialize() and beforeexecute(). Its purpose is to check if some of the options/arguments are missing and interactively ask the user for those values. This is the last place where you can ask for missing options/arguments. After this command, missing options/arguments will result in an error.

execute() (required)

This method is executed after interact() andinitialize(). It contains the logic you want the command to execute and it must return an integer which will be used as the command exit status.

Testing Commands

Symfony provides several tools to help you test your commands. The most useful one is the Symfony\Component\Console\Tester\CommandTester class. It uses special input and output classes to ease testing without a real console:

  1. // tests/Command/CreateUserCommandTest.php
  2. namespace App\Tests\Command;
  3. use Symfony\Bundle\FrameworkBundle\Console\Application;
  4. use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
  5. use Symfony\Component\Console\Tester\CommandTester;
  6. class CreateUserCommandTest extends KernelTestCase
  7. {
  8. public function testExecute()
  9. {
  10. $kernel = static::createKernel();
  11. $application = new Application($kernel);
  12. $command = $application->find('app:create-user');
  13. $commandTester = new CommandTester($command);
  14. $commandTester->execute([
  15. // pass arguments to the helper
  16. 'username' => 'Wouter',
  17. // prefix the key with two dashes when passing options,
  18. // e.g: '--some-option' => 'option_value',
  19. ]);
  20. // the output of the command in the console
  21. $output = $commandTester->getDisplay();
  22. $this->assertStringContainsString('Username: Wouter', $output);
  23. // ...
  24. }
  25. }

If you are using a single-command application, call setAutoExit(false) on it to get the command result inCommandTester`.

New in version 5.2: The `setAutoExit() method for single-command applications was introduced in Symfony 5.2.

Tip

You can also test a whole console application by using Symfony\Component\Console\Tester\ApplicationTester.

Caution

When testing commands using the CommandTester class, console events are not dispatched. If you need to test those events, use the Symfony\Component\Console\Tester\ApplicationTester instead.

Caution

When testing commands using the Symfony\Component\Console\Tester\ApplicationTester class, don’t forget to disable the auto exit flag:

  1. $application = new Application();
  2. $application->setAutoExit(false);
  3. $tester = new ApplicationTester($application);

Note

When using the Console component in a standalone project, use Symfony\Component\Console\Application and extend the normal \PHPUnit\Framework\TestCase.

Logging Command Errors

Whenever an exception is thrown while running commands, Symfony adds a log message for it including the entire failing command. In addition, Symfony registers an event subscriber to listen to the ConsoleEvents::TERMINATE event and adds a log message whenever a command doesn’t finish with the 0 exit status.

Learn More

The console component also contains a set of “helpers” - different small tools capable of helping you with different tasks:

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.