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
 */
class SendSlackNotificationCommand extends Command
{
    private const STATUS_OK            = 0;
    private const STATUS_ERROR         = -1;
    private const STATUS_NOTHING_TO_DO = -2;

    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)
    {
        parent::__construct();
        $this->slackLogger = $slackLogger;
    }

    protected function configure(): void
    {
        $namespace = self::NAMESPACE;
        $cmd = self::CMD;
        $desc = self::DESC;
        $arg1 = self::ARGS[self::ARG1_KEY];
        $this
            ->setName($namespace.':'.$cmd)
            ->setDescription(self::DESC)
            ->addArgument(self::ARG1_KEY, InputArgument::REQUIRED, self::ARGS[self::ARG1_KEY])
            ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')
            ->setHelp(
                <<<EOT
{$desc}

DEV:
<info>php bin/console {$namespace}:{$cmd} "{$arg1}" -v</info>

PROD:
<info>php bin/console {$namespace}:{$cmd} "{$arg1}" --no-debug</info>
EOT
            );
    }

    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. 🙃
        $this->slackLogger->info($message);
        $io->note($message);
        $io->success(' -> DONE!');

        return self::STATUS_OK;
    }
}
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);
        $app->add($this->sendSlackNotificationCommand);
        $command = $app->find(SendSlackNotificationCommand::NAMESPACE.':'.SendSlackNotificationCommand::CMD);
        $commandTester = new CommandTester($command);
        $commandTester->execute([
            '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.
        echo $commandTester->getDisplay(); // That's it! 😁
    }
}

 Run this snippet  More on Stackoverflow   Read the doc