[Symfony] créer une commande accessible Symfony 4
Parfois nous avons besoin de faire un script PHP. Vous pouvez tout a fait faire un script qui peut être appelé en ligne de commande grâce à CLI ou vous pouvez créer une commande Symfony. Cela vous permettra d’utiliser les composant de Symfony et tout vos composant qui vous avez mis tant de temps à créer 🙂 .
Voyons comment créer une commande Symfony.
Objectif de notre script
L’objectif de notre script va être simple, nous allons afficher X nombre de la suite Fibonacci. Où X est un nombre qui serra passé en paramètre à notre script.
Définition : La suite de Fibonacci est une suite d’entiers dans laquelle chaque terme est la somme des deux termes qui le précèdent. Elle commence généralement par les termes 0 et 1 (parfois 1 et 1) et ses premiers termes sont : 0, 1, 1, 2, 3, 5, 8, 13, 21, etc.
Commande basique
Pour créer une commande Symfony vous devez créer une classe qui étant la classe ‘Command’. Ci dessous, le code permettant d’afficher les 5 première itérations de fibonacci. Essayez de comprendre le code avant de lire les explication en dessous.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class FibonacciCommand extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:fibonacci'; protected function configure() { // ... } protected function execute(InputInterface $input, OutputInterface $output) { // nombre de nombre de la suite a afficher $totalIteration = 5; $previousNumber = 0; $currentNumber = 1; $output->writeln("Voici les " . $totalIteration . " premiers nombres de la suite de Fibonacci."); for($i = 1; $i<=$totalIteration; $i++) { $calc = $previousNumber + $currentNumber; $previousNumber = $currentNumber; $currentNumber = $calc; $output->writeln($currentNumber); } } } |
Explications :
ligne 12 : on déclare le nom de la commande. Ce nom serra appelé via la commande php bin/console {commande_name}. Dans notre cas, cela sera php bin/console app:fibonacci.
ligne 15 à 17 : on déclare la fonction qui permet de configurer notre commande. Nous la laissons pour le moment à vide.
ligne 19 à 33 : on déclare le cœur de notre commande. Ci dessous, le code commenté
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class FibonacciCommand extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:fibonacci'; protected function configure() { // ... } protected function execute(InputInterface $input, OutputInterface $output) { // nous démarrons la suite à 1 pour pouvoir faire les calcules par la suite $totalIteration = 5; // nombre d’itérations de la suite a afficher $previousNumber = 0; // nombre précédent de la suite de fibonacci $currentNumber = 1; // nombre courant de la suite de fibonacci $output->writeln("Voici les " . $totalIteration . " premiers nombres de la suite de Fibonacci."); for($i = 1; $i<=$totalIteration; $i++) // on fait $totalIteration itérations { $calc = $previousNumber + $currentNumber; // on calcul la prochaine itération $previousNumber = $currentNumber; // on met le nombre courant dans le nombre de l'itération précédente $currentNumber = $calc; // on met le calcul de la nouvelle itération dans l'iteration courante (on passe à l'itération suivante) $output->writeln($currentNumber); // on affiche la nouvelle itération } } } |
Essayez notre toute belle commande et elle devrait donner le résultat ci-dessous :
Améliorons la documentation de notre commande
Notre commande est pour le moment limité, nous l’améliorerons par la suite. Le plus important pour le moment est de la documenter. Hé oui, a quoi ça sert de faire une commande si personne ne sait comment elle fonctionne. En plus on le sais tous, dans 6 mois, nous aurons oublié ce que fait notre commande et nous devrons relire le code pour savoir ce qu’elle fait …
Dites NON aux mauvaises pratiques et documenté ! (oui ça fait slogan, mais j’y tien ^^).
Ajoutons une Description de notre commande. Dans la méthode configure, ajoutez une description comme ci-dessous :
1 2 3 4 5 |
protected function configure() { $this ->setDescription('Affiche les 5 premières itérations de la suite de fibonacci.'); } |
Cette description sera alors visible si nous listons les commandes disponible à l’aide de “php bin/console list” :
Ajoutons une description supplémentaire expliquant notre commande lorsque l’utilisateur demandera l’aide sur notre commande.
Pour cela complétons notre méthode configure une nouvelle fois :
1 2 3 4 5 6 |
protected function configure() { $this ->setDescription('Affiche les 5 premières itérations de la suite de fibonacci.') ->setHelp('Cette commande peremet d\'afficher des occurences de la suite de fiboncci.'); } |
Maintenant lorsque vous demanderez l’aide de votre commande, vous verrez ceci :
Passons le nombre d’itération en argument de notre commande
Nous pouvons ajouter des options a notre commande. Pour cela nous allons utiliser ‘addArgument’ dans notre configuration et récupérer cette argument via ‘$input->getArgument’ :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; class FibonacciCommand extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:fibonacci'; protected function configure() { $this ->setDescription('Affiche les 5 premières itérations de la suite de fibonacci.') ->setHelp('Cette commande peremet d\'afficher des occurences de la suite de fiboncci.') ->addArgument('iterations', InputArgument::REQUIRED, 'Nombre d\'itérations à afficher.'); } protected function execute(InputInterface $input, OutputInterface $output) { // nous démarrons la suite à 1 pour pouvoir faire les calcules par la suite $totalIteration = $input->getArgument('iterations'); // nombre d'iterations de la suite a afficher $previousNumber = 0; // nombre précédent de la suite de fibonacci $currentNumber = 1; // nombre courant de la suite de fibonacci $output->writeln("Voici les " . $totalIteration . " premiers nombres de la suite de Fibonacci."); for($i = 1; $i<=$totalIteration; $i++) // on fait $totalIteration itérations { $calc = $previousNumber + $currentNumber; // on calcul la prochaine itération $previousNumber = $currentNumber; // on met le nombre courant dans le nombre de l'itération précédente $currentNumber = $calc; // on met le calcul de la nouvelle itération dans l'iteration courante (on passe à l'itération suivante) $output->writeln($currentNumber); // on affiche la nouvelle itération } } } |
A la ligne 20, nous ajoutons un argument obligatoire avec un petite description qui sera visible dans l’aide la commande.
A la ligne 26, a la place d’un nombre statique nous récupérons le nombre d’itération passé en paramètre.
Exécuté a nouveau votre commande ‘php bin/console app:fibonacci’ et vous obtenez …. Une erreur 😡
Restez calme, c’est parce que nous avons oublié d’ajouter notre nombre d’itération qui est obligatoire en argument . Ajoutez le nombre d’itération souhaité et testez à nouveau. Voilà nous obtenons le résultat ci dessous :
Vous pouvez trouver les différents modes d’arguments (second paramètre de ‘addArgument’) dans la classe ‘Symfony\Component\Console\Input\InputArgument’. Je vous laisse cherchez un peux, histoire de ne pas tout vous donner non plus 🙂
Utiliser des options
En plus des arguments, vous disposez également des options que vous pouvez utiliser dans votre script. L’avantage ds options est d’avoir plus de visibilité (puisque l’on précise le nom de l’option par rapport au paramètre) et de ne pas être ordonné. En effet pouvez écrire ‘php bin/console ma_commande –option1=valeur1 –option2=valeur2’ ou ‘php bin/console ma_commande –option2=valeur2 –option1=valeur1’ et vous obtiendrez le même résultat.
Pour notre exemple nous allons ajouter une option permettant d’afficher les itérations de fibonacci sur une ligne plutôt que de passer à la ligne à chaque itération. Pour cela, ajoutez une option dans la méthode ‘configure’ via ‘addOption’ et récupérez le paramètre dans le corps de votre commande :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Doctrine\ORM\EntityManagerInterface ; use Symfony\Component\Console\Input\InputOption; class FibonacciCommand extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:fibonacci'; protected function configure() { $this ->setDescription('Affiche les 5 premières itérations de la suite de fibonacci.') ->setHelp('Cette commande peremet d\'afficher des occurences de la suite de fiboncci.') ->addArgument('iterations', InputArgument::REQUIRED, 'Nombre d\'itérations à afficher.') ->addOption('inline', 'i', InputOption::VALUE_OPTIONAL, 'Si cette option est définit a TRUE, les itération seront afficher sur une seul et unique ligne.', false); } protected function execute(InputInterface $input, OutputInterface $output) { $inline = $input->getOption('inline'); // nous démarrons la suite à 1 pour pouvoir faire les calcules par la suite $totalIteration = $input->getArgument('iterations'); // nombre d'iterations de la suite a afficher $previousNumber = 0; // nombre précédent de la suite de fibonacci $currentNumber = 1; // nombre courant de la suite de fibonacci $output->writeln("Voici les " . $totalIteration . " premiers nombres de la suite de Fibonacci."); for($i = 1; $i<=$totalIteration; $i++) // on fait $totalIteration itérations { $calc = $previousNumber + $currentNumber; // on calcul la prochaine itération $previousNumber = $currentNumber; // on met le nombre courant dans le nombre de l'itération précédente $currentNumber = $calc; // on met le calcul de la nouvelle itération dans l'iteration courante (on passe à l'itération suivante) if ($inline == false) { $output->writeln($currentNumber); // on affiche la nouvelle itération } else { $output->write($currentNumber . ' '); // on affiche la nouvelle itération } } } } |
ligne 23 : nous ajoutons une option à notre commande. Le premier argument est le nom de l’option. Le second est l’alias de l’option (ici, nous pourrons utiliser -i à la place de –inline). Le 3ème argument est le mode, par exemple ici nous souhaitons que notre option soit optionnel. Le 4ème argument est une description de notre option qui apparentera dans l’aide de la commande. Le dernier argument est la valeur par défaut de notre option. Il est a noter que seul le premier argument est obligatoire 🙂
ligne 28 : nous récupérons la valeur de l’option.
ligne 33 : en fonction de la valeur de notre option, nous affichons les itérations avec ou sans sauts de ligne.
Testons notre commandes 🙂
Utiliser d’autres services dans votre commande
Pour utiliser des services dans votre commande, vous pouvez les injecter de la même manière que pour vos contrôleurs. Pour être plus concret, surcharger le contrôleur de la commande pour y injecter vos dépendances :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?php namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Doctrine\ORM\EntityManagerInterface ; class FibonacciCommand extends Command { // the name of the command (the part after "bin/console") protected static $defaultName = 'app:fibonacci'; protected $em; public function __construct(EntityManagerInterface $em) { $this->em = $em; parent::__construct(); } protected function configure() { $this ->setDescription('Affiche les 5 premières itérations de la suite de fibonacci.') ->setHelp('Cette commande peremet d\'afficher des occurences de la suite de fiboncci.') ->addArgument('iterations', InputArgument::REQUIRED, 'Nombre d\'itérations à afficher.'); } protected function execute(InputInterface $input, OutputInterface $output) { // nous démarrons la suite à 1 pour pouvoir faire les calcules par la suite $totalIteration = $input->getArgument('iterations'); // nombre d'iterations de la suite a afficher $previousNumber = 0; // nombre précédent de la suite de fibonacci $currentNumber = 1; // nombre courant de la suite de fibonacci $output->writeln("Voici les " . $totalIteration . " premiers nombres de la suite de Fibonacci."); for($i = 1; $i<=$totalIteration; $i++) // on fait $totalIteration itérations { $calc = $previousNumber + $currentNumber; // on calcul la prochaine itération $previousNumber = $currentNumber; // on met le nombre courant dans le nombre de l'itération précédente $currentNumber = $calc; // on met le calcul de la nouvelle itération dans l'iteration courante (on passe à l'itération suivante) $output->writeln($currentNumber); // on affiche la nouvelle itération } } } |
Tips
Afficher un résultat sans aller à la ligne
Vous pouvez utilisez ‘$output->write’ au lieu de ‘$output->writeln’ pour afficher du texte sans aller à ligne.
C’est tout pour cette fois, j’envisage de faire un article supplémentaire sur les sous commande Symfony. C’est à dire vous présentez comment lancer des commandes depuis votre commande principal afin de découpler votre code au mieux et profiter pleinement de tout les processeurs de votre machines.