My Symfony command template

Published on 2019-11-24 • Modified on 2019-11-24

You can generate a command with the maker bundle (php bin/console make:command). I use a slightly different template where the help text is dynamically generated with constants. These ones are also used as parameters to set the different options so you don't have duplicated code. Remove the constructor parameter as it is specific to this blog (It's a parameter binded in services.yaml). To run the command I will use a CommandTester this time instead of using the Process component.

<?php declare(strict_types=1);

// src/Command/SendSlackNotificationCommand.php

namespace App\Command;

use Monolog\Logger;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

 * @see SendSlackNotificationCommand::DESC
final class SendSlackNotificationCommand extends Command
    public const NAMESPACE  = 'strangebuzz'; // used by command tester
    public const CMD        = 'send-slack';
    private const DESC      = 'Send a message on a Slack channel.';
    private const ARG1_KEY  = 'message';
    private const ARGS = [
       self::ARG1_KEY => 'The message to send'

    private $slackLogger;

    public function __construct(Logger $slackLogger)
        $this->slackLogger = $slackLogger;

    protected function configure(): void
        $desc = self::DESC;
        $arg1 = self::ARGS[self::ARG1_KEY];
            ->addArgument(self::ARG1_KEY, InputArgument::REQUIRED, self::ARGS[self::ARG1_KEY])
            ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')

<info>%command.full_name% "{$arg1}" -v</info>

<info>%command.full_name% "{$arg1}" --no-debug</info>

    protected function execute(InputInterface $input, OutputInterface $output): int
        $io = new SymfonyStyle($input, $output);
        $message = $input->getArgument(self::ARG1_KEY);
        $message = \is_string($message) ? $message : ''; // You know, for PHPStan. 🙃
        $io->success(' -> DONE!');

        return 0;
Bonus, the snippet to run this code: 🎉
<?php declare(strict_types=1);

namespace App\Controller\Snippet;

use App\Command\SendSlackNotificationCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\HttpKernel\KernelInterface;

 * I am using a PHP trait in order to isolate each snippet in a file.
 * This code should be called from a Symfony controller extending AbstractController (as of Symfony 4.2)
 * or Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
 * Services are injected in the main controller constructor.
 * @property KernelInterface              $kernel
 * @property SendSlackNotificationCommand $sendSlackNotificationCommand
trait Snippet58Trait
    public function snippet58(): void
        $app = new Application($this->kernel);
        $command = $app->find(SendSlackNotificationCommand::NAMESPACE.':'.SendSlackNotificationCommand::CMD);
        $commandTester = new CommandTester($command);
            'command' => $command->getName(),
            'message' => 'Hello World!'

        // Sorry the output doesn't look great but it will be the case when running
        // it from your console thanks to the Symfony style. If you want the nice
        // ANSI output use the process component (check out the Makefile snippet).

        echo $commandTester->getDisplay(); // That's it! 😁