Mon template de commande Symfony
Publié le 24/11/2019 • Actualisé le 24/11/2019
On peut générer une commande avec le bundle Maker (php bin/console make:command
). J'utilise un template légérement différent ou le texte d'aide est généré dynamiquement avec des constantes. Celles-ci sont aussi utilisées en tant que paramétres des différentes options afin de ne pas avoir de code dupliqué. Supprimez le paramètre du constructeur, il est spécifique à ce blog (c'est un paramètre "nommé" dans le fichier services.yaml
). Pour lancer ce snippet, j'utiliserai cette fois un testeur de commandes (CommandTester
) au lieu d'utiliser le composant Process
.
<?php
declare(strict_types=1);
// src/Command/ShowVersionCommand.php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Helper\TableSeparator;
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;
/**
* Displays the current application version. This is also the template I copy/paste
* when having to write a new command.
*/
#[AsCommand(
name: self::NAMESPACE.':'.self::CMD,
description: self::DESCRIPTION)
]
final class ShowVersionCommand extends BaseCommand
{
public const string CMD = 'version';
public const string DESCRIPTION = 'Shows the current application version number.';
// BaseCommand is an abstract class extending Symfony\Component\Console\Command\Command
// and contains the project main namespace
private string $appVersion;
public function __construct(string $appVersion)
{
$this->appVersion = $appVersion;
parent::__construct();
}
protected function configure(): void
{
[$desc, $class] = [self::DESCRIPTION, self::class];
$this
// InputArgument::REQUIRED / OPTIONAL / IS_ARRAY (3)
->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description')
// InputOption::VALUE_NONE / VALUE_REQUIRED / VALUE_OPTIONAL / VALUE_IS_ARRAY / VALUE_NEGATABLE (5)
->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')
->setHelp(
<<<EOT
$desc
COMMAND:
<comment>$class</comment>
DEV:
<info>%command.full_name% -vv</info>
PROD:
<info>%command.full_name% --env=prod --no-debug</info>
EOT
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->title(self::DESCRIPTION);
if ($output->isVerbose()) {
$io->note('This note will only be displayed when using at least the verbose mode option for the command "-v"');
// if you want to test on a given level only, use:
// if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERBOSE)
}
if ($output->isVerbose()) {
$io->note('This note will only be displayed when using at least the verbose mode option for the command "-v"');
}
$output->writeln('This line will only be displayed when using at least the verbose mode option for the command "-v"', OutputInterface::VERBOSITY_VERBOSE);
// snippet L62+9 used in templates/snippet/code/_164.html.twig
$io->section('Version');
$io->note(BaseCommand::NAMESPACE.' '.$this->appVersion);
$io->newLine();
$io->section('Let test the SymfonyStyle for CLI now, this is a section');
$io->title('This is a title');
$io->block('This is a block');
$io->newLine(2);
$io->text('This is a text (two new lines before)');
$io->comment('This is a comment');
$io->caution('This is a caution');
$io->error('This is an error');
$io->info('This is an info');
$io->note('This is a note');
$io->listing(['this', 'is', 'a', 'listing']);
$io->table(
['This', 'is', 'a', 'table'],
[
['Cell 1-1', 'Cell 1-2', 'Cell 1-3', 'Cell 1-4'],
['Cell 2-1', 'Cell 2-2', 'Cell 2-3', 'Cell 2-4'],
['Cell 3-1', 'Cell 3-2', 'Cell 2-3', 'Cell 3-4'],
]
);
$io->horizontalTable(
['This is an', 'horizontal Table'],
[
['Cell 1-1', 'Cell 1-2'],
['Cell 2-1', 'Cell 2-2'],
['Cell 3-1', 'Cell 3-2'],
]
);
$io->definitionList(
'This is a definition list',
['foo1' => 'bar1'],
['foo2' => 'bar2'],
['foo3' => 'bar3'],
new TableSeparator(),
'with keys => values',
['foo4' => 'bar4']
);
$io->success('This is a success');
$io->section("That's all folks!");
return self::SUCCESS;
}
}
En bonus, le snippet permettant d'utiliser ce code : 🎉<?php
declare(strict_types=1);
namespace App\Controller\Snippet;
use App\Command\ShowVersionCommand;
use SensioLabs\AnsiConverter\AnsiToHtmlConverter;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Process\Process;
/**
* J'utilise un trait PHP afin d'isoler chaque snippet dans un fichier.
* Ce code doit être apellé d'un contrôleur Symfony étendant AbstractController (depuis Symfony 4.2)
* ou Symfony\Bundle\FrameworkBundle\Controller\Controller (Symfony <= 4.1).
* Les services sont injectés dans le constructeur du contrôleur principal.
*
* @property KernelInterface $kernel
* @property ShowVersionCommand $showVersionCommand
*/
trait Snippet58Trait
{
public function snippet58(): void
{
$process = new Process([
'php',
$this->kernel->getProjectDir().'/bin/console',
'strangebuzz:version',
'--ansi',
]);
$process->run();
echo (new AnsiToHtmlConverter())->convert($process->getOutput()); // That's it! 😁
}
}
Exécuter le snippet ≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫ Plus sur Stackoverflow Lire la doc Snippet aléatoire
<?php
declare(strict_types=1);
namespace App\Tests\Integration\Controller\Snippets;
use App\Command\SendSlackNotificationCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
/**
* @see Snippet58Trait
*/
final class Snippet58Test extends KernelTestCase
{
/**
* @see Snippet58Trait::snippet58
*/
public function testSnippet58(): void
{
$app = new Application(self::createKernel());
$command = $app->find(SendSlackNotificationCommand::NAME);
$commandTester = new CommandTester($command);
$message = 'Hello World!';
$commandTester->execute([
'command' => $command->getName(),
'message' => $message,
]);
self::assertStringContainsStringIgnoringCase($message, $commandTester->getDisplay());
}
}
A vous de jouer !
Ces articles vous ont été utiles ? Vous pouvez m'aider à votre tour de plusieurs manières : (cliquez sur le lien "reply" dans à droite pour me contacter )
- Me remonter des erreurs ou typos.
- Me remonter des choses qui pourraient être améliorées.
- Aimez et repostez !
- Suivez moi sur Bluesky 🦋
- Inscrivez-vous au flux RSS.
- Cliquez sur les boutons Plus sur Stackoverflow pour me faire gagner des badges "annonceur" 🏅.
Merci et à très bientôt sur Strangebuzz ! 😉
