Aller au contenu principal

La console Symfony et les commandes personnalisées

Comment fonctionne bin/console et comment créer sa propre commande

Notions théoriques

Qu'est-ce que bin/console ?

Depuis le début de ce cours, vous tapez régulièrement des commandes comme :

php bin/console make:controller
php bin/console make:entity

bin/console est le point d'entrée en ligne de commande de Symfony. C'est un simple fichier PHP qui démarre l'application, mais au lieu de répondre à une requête HTTP (comme le fait public/index.php), il exécute une commande demandée dans le terminal.

info

Chaque commande (make:controller, make:entity, cache:clear, debug:router...) est en réalité une classe PHP. Symfony fournit de nombreuses commandes prêtes à l'emploi, mais vous pouvez aussi créer les vôtres.

Une commande sert à automatiser une tâche technique : générer du code, nettoyer le cache, importer des données, envoyer un rapport par email, etc. C'est un outil pour le développeur ou pour l'administrateur du site, pas pour le visiteur final.

Lister et explorer les commandes disponibles

Pour voir la liste complète des commandes disponibles dans un projet Symfony :

php bin/console list

Les commandes sont regroupées par espace de noms (make:, cache:, doctrine:, debug:...). Ce préfixe indique la famille à laquelle appartient la commande.

Pour obtenir de l'aide détaillée sur une commande précise (ses arguments, ses options) :

php bin/console make:controller --help
astuce

--help fonctionne avec toutes les commandes, y compris celles que vous créerez vous-même. C'est le réflexe à avoir avant d'utiliser une commande inconnue.

Créer sa propre commande

Symfony fournit un générateur pour créer le squelette d'une nouvelle commande :

php bin/console make:command app:mission-du-jour

Cette commande génère un nouveau fichier dans src/Command/, par exemple src/Command/MissionDuJourCommand.php, prêt à être complété.

Anatomie d'une classe de commande

Une classe de commande Symfony a toujours la même structure :

  • L'attribut #[AsCommand(name: '...', description: '...')] déclare le nom de la commande (celui tapé dans le terminal) et sa description (affichée dans php bin/console list).
  • La méthode configure() définit les arguments et options attendus par la commande.
  • La méthode execute() contient la logique métier de la commande : c'est le code qui s'exécute réellement.
  • La classe SymfonyStyle (généralement injectée via $io = new SymfonyStyle($input, $output);) permet un affichage propre dans le terminal : $io->success(...), $io->error(...), $io->title(...), $io->table(...).
info

execute() doit retourner une constante entière : Command::SUCCESS, Command::FAILURE ou Command::INVALID. C'est ce code de retour que d'autres outils (scripts, tâches planifiées) utilisent pour savoir si la commande s'est bien déroulée.

Exemple de mise en application

Créons une commande app:count-players qui affiche le nombre total de joueurs enregistrés en base de données. Elle réutilise le PlayerRepository déjà utilisé par le GameController.

// src/Command/CountPlayersCommand.php
namespace App\Command;

use App\Repository\PlayerRepository;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(
name: 'app:count-players',
description: 'Affiche le nombre total de joueurs enregistrés en base de données',
)]
class CountPlayersCommand extends Command
{
public function __construct(
private PlayerRepository $playerRepository
) {
parent::__construct();
}

protected function configure(): void
{
// Aucun argument ni option pour cette commande simple
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

$total = count($this->playerRepository->findAll());

$io->success(sprintf('Il y a actuellement %d joueur(s) enregistré(s).', $total));

return Command::SUCCESS;
}
}

Grâce à l'injection de dépendances, Symfony fournit automatiquement une instance de PlayerRepository au constructeur de la commande, exactement comme il le fait pour un contrôleur.

Pour exécuter cette commande :

php bin/console app:count-players
astuce

Une commande personnalisée apparaît automatiquement dans php bin/console list, regroupée sous l'espace de noms app: si vous suivez cette convention de nommage.

Test de mémorisation/compréhension


Qu'est-ce que `bin/console` dans un projet Symfony ?


Quelle commande permet de lister toutes les commandes disponibles ?


Comment obtenir l'aide détaillée d'une commande spécifique ?


Quelle commande permet de générer le squelette d'une nouvelle commande personnalisée ?


Quel attribut déclare le nom et la description d'une commande Symfony ?


Dans quelle méthode place-t-on la logique métier d'une commande ?


À quoi sert la classe SymfonyStyle dans une commande ?


Que doit retourner la méthode execute() d'une commande ?


TP pour réfléchir et résoudre des problèmes

Votre défi pour aujourd'hui consiste à créer une commande app:count-characters qui affiche le nombre total de personnages enregistrés en base de données, en réutilisant le CharacterRepository déjà présent dans le projet.

Étape 1 — Générer le squelette de la commande

Ouvrez un terminal à la racine du projet et générez la commande avec le générateur Symfony.


Bonne pratique - Préfixer ses commandes par app:

Utiliser le préfixe app: pour toutes les commandes personnalisées du projet permet de les distinguer immédiatement des commandes internes de Symfony (make:, doctrine:, cache:...) lorsqu'on parcourt la liste avec php bin/console list.

Étape 2 — Injecter le CharacterRepository

Pour accéder aux personnages en base de données, la commande a besoin du CharacterRepository, comme un contrôleur en aurait besoin.


Bonne pratique - Toujours appeler parent::__construct()

Lorsqu'une commande a un constructeur personnalisé, il est impératif d'appeler parent::__construct(). Sans cet appel, la commande ne sera pas correctement enregistrée et Symfony lèvera une erreur au démarrage.

Étape 3 — Écrire la logique dans execute()

Complétez la méthode execute() pour compter les personnages et afficher le résultat avec SymfonyStyle.


Bonne pratique - Toujours retourner un code de sortie explicite

Ne jamais oublier return Command::SUCCESS; (ou Command::FAILURE en cas d'erreur) à la fin de execute(). Ce code de retour est utilisé par les scripts d'automatisation ou les tâches planifiées pour savoir si la commande s'est bien terminée.

📌 Une solution