Commentaires
Une avancée de Symfony 2.5... parmi d'autres
Pour ce dernier article du calendrier de l'avent de l'AFSY, j'ai envie de parler de Symfony 2.5. Le développement de cette nouvelle version qui sortira en mai 2014 vient juste de commencer, mais on peut déjà noter certains changements intéressants. Sachez que toutes les nouvelles fonctionnalités seront "retro-compatible", comme pour la version 2.4.
Ces premières semaines de développement ont permis d'ajouter de petites fonctionnalités qui peuvent se révéler très intéressantes ; en vrac :
- La détection par le composant Debug de l'utilisation de méthodes non définies (#9779);
- Le support natif de l'upload simultané de plusieurs fichiers dans un formulaire (#8224);
- La possibilité de renommer le process d'une commande (de la Console); bien pratique pour les daemons (#9780);
- La suppression des barres de progression quand la console ne supporte pas les codes ANSI (#9846);
- et quelques autres que je vous laisse le soin d'aller voir (#9739, #9773, #9843), et #9650.
Bref, cette version 2.5 s'annonce déjà riche en avancées diverses... et j'ai bien sûr quelques surprises dans ma besace. Que diriez-vous d'avoir un aperçu d'une nouvelle fonctionnalité sur laquelle je travaille en ce moment et qui devrait se transformer en pull request dans les prochains jours ? Ok, c'est parti.
Il n'est pas rare de lancer des "process" externes lorsqu'on exécute une commande Symfony; un truc du genre :
$process = new Process('ls -lsa');
$process->run();
$output->writeln($process->getOutput());
Tant que tout se passe comme prévu, pas de souci. Mais si un problème survient durant l'exécution de ce process, galère. Hormis l'ajout d'un echo
par ci, et d'un var_dump()
par là, difficile de comprendre le problème.
Voici néanmoins une manière assez élégante :
$callback = function ($type, $buffer) use ($output) {
$output->write($buffer);
};
$process->run(OutputInterface::VERBOSITY_VERBOSE < $output->getVerbosity() ? $callback : null);
Et pour avoir une jolie sortie qui ne mélange pas la sortie standard avec la sortie d'erreur, voici un bout de code extrait de Sismo :
$callback = function ($type, $buffer) use ($output, &$startedOut, &$startedErr) {
if ('err' === $type) {
if (!$startedErr) {
$output->write("\n<bg=red;fg=white> ERR </> ");
$startedErr = true;
$startedOut = false;
}
$output->write(str_replace("\n", "\n<bg=red;fg=white> ERR </> ", $buffer));
} else {
if (!$startedOut) {
$output->write("\n<bg=green;fg=white> OUT </> ");
$startedOut = true;
$startedErr = false;
}
$output->write(str_replace("\n", "\n<bg=green;fg=white> OUT </> ", $buffer));
}
};
La sortie ressemble alors à quelque chose de ce genre :
Plutôt que de copier/coller ce bout de code dans chaque projet, je vais proposer de l'intégrer à Symfony 2.5 via un nouveau helper debug_formatter
.
Je vous parlerais plus tard de ce formatteur, car dans ce cas précis, Symfony 2.5 fournira un helper process
qui englobe ce comportement par défaut :
$helper = $this->getHelper('process');
$process = $helper->run($output, 'ls -lsa');
$output->writeln($process->getOutput());
Et voilà. Pour activer le mode debug, il suffit de passer le flag -vv
:
$ ./app/console ... -vv
Pour obtenir le détail de la sortie standard et de la sortie d'erreur, utilisez -vvv
:
$ ./app/console ... -vvv
Et en cas de problème, les couleurs changent pour votre plus grand plaisir :
Le helper vous laisse la main si vous souhaitez créer votre propre instance de Process
:
$helper = $this->getHelper('process');
$process = new Process('ls -lsa');
$helper->run($output, $process);
$output->writeln($process->getOutput());
Vous pouvez même passer une callback qui sera ajoutée automatiquement à celle par défaut définie par le helper :
$callback = function ($type, $buffer) {
error_log($buffer);
};
$helper->run($output, $process, null, $callback);
Mais alors, pourquoi avoir créé un helper process
et un helper debug_formatter
? Parce qu'il est réutilisable... par exemple pour pouvoir debugger un appel HTTP réalisé avec Guzzle :
use Guzzle\Http\Client;
$client = new Client();
$client->addSubscriber(new GuzzleConsolePlugin(
$output,
$this->getHelper('debug_formatter'))
);
$client->get('http://example.com/')->send();
Bam ! Un appel à Guzzle du style :
$client->get('http://example.com/')->send();
va maintenant pouvoir être debuggé avec les mêmes outils que nous venons de voir. Essayez de lancer votre commande avec -vv
:
Avez-vous remarqué la bande de couleur sur la gauche de l'affichage ? Ce n'est pas qu'un effet de style, cela permet également de différencier un appel principal des appels secondaires :
Vous aimez ? Ce n'est que la partie visible de ces nouveaux helpers. Si vous souhaitez utiliser le debug_formatter
pour vos propres besoins, rien de plus simple :
$formatter = $this->getHelperSet()->get('debug_formatter');
// start a session
$start = $formatter->start($uuid, $cmd);
$output->write($start);
// give some feedback
$progress = $formatter->progress($uuid, $buffer, $isError);
$output->write($progress);
// at the end
$stop = $formatter->stop($uuid, $message, $isSuccessful);
$output->write($stop);
Pas la peine d'essayer chez vous ce soir, le code n'est pas encore disponible ; profitez-en pour passer un joyeux Noël avec vos proches !