Symfony Process : Comment exécuter du shell dans son code

Gary Houbre
3 min readApr 21, 2021

--

Symfony Process permet d’exécuter des scripts python, shell, exécuter des commandes etc… Ce qui permet d’ajouter une corde à votre arc lorsque vous développez votre application web.

Installation

Pour installer le composant Process rien de plus simple :

composer require symfony/process

Utilisation

Pour cet article on va prendre exemple, un script shell qui me permet d’afficher “Hello World” sur mon terminal (l’idée est géniale, j’en ai conscience). Ce script shell il est dans mon dossier public/helloworld.sh (avec les droits d’exécution).

// public/helloworld.sh 
#!/bin/bash
echo "Hello World"

Utilisons le composant dans un controller :

// src/Controller/HelloWorldController.php
namespace App\Controller;
// ...
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class HelloWorldController extends AbstractController
{
public function hello(Request $request)
{
$pathToHelloWorldScript = "/.../myproject/public/helloworld.sh";
$process = new Process(['sh', $pathToHelloWorldScript]);
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
// Cela affichera "Hello World"
echo $process->getOutput();
// ...
}
}

Lorsqu’on utilise le composant Process, il va créer un sous processus qui va lancer votre commande, ce sous processus va être autonome mais sans la fonction isSuccessful(), la fonction aurait retourner null ou notre valeur.

Utilisons maintenant dans une commande, désormais le script, on va lui ajouter quelques détails qu’il permettra de trier le retour de la commande.

Info : Un article est disponible concernant les commandes : Lien

// src/Command/HelloCommand.php
namespace App\Command;
// ...
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class HelloCommand extends Command
{
protected static $defaultName = "app:hello";
protected function configure()
{
//...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$process = new Process(['ls', '-lsa']);
$process->start();
foreach ($process as $type => $data) {
if ($process::OUT === $type) {
echo "\nDebug :".$data;
} else { // $process::ERR === $type
echo "\nErreur : ".$data;
}
}
// Depuis Symfony 5.2, vous pouvez utiliser directement la variable Command::SUCCESS
return 0;
}
}

En utilisant cette fonction $process->start(), cela lancera en tâche de fond la commande que vous avez faite (pour ma part ls -la) et poursuivre votre commande.

Tant que le process sera en runtime (actif), il restera dans le foreach. Il affichera les retours de votre process avec un tri par le type ($type).

Poussons le vice

Désormais, nous allons plus loin. Notre composant Process a une fonction qui s’appelle waitUntil, une fonction qui peut exécuter une fonction anonyme qui permet de rester dans le process tant qu’il n’est pas true.

Nous allons crée un nouveau script bash simple comme ci-dessous :

// public/helloworld.sh
#!/bin/bash
echo "Begin Processus"i=0while [ $i -le 30 ]
do
let "i+=1"
done
echo "The Script is finish."// src/Controller/HelloWorldController.php
namespace App\Controller;
// ...
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class HelloWorldController extends AbstractController
{
public function hello(Request $request)
{
$pathToHelloWorldScript = "/.../myproject/public/helloworld.sh";
$process = new Process(['sh', $pathToHelloWorldScript]);
$process->start();
$process->waitUntil(function ($type, $output) {
// Tant que ce n'est pas true, je reste dans cette fonction anonyme.
return $output === 'The Script is finish.';
});

// ...
}
}

Cependant, si on voudrait stop le process, une fonction le permet : $process-> stop()

// src/Command/HelloCommand.php
namespace App\Command;
// ...
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class HelloCommand extends Command
{
protected static $defaultName = "app:hello";
protected function configure()
{
//...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$process = new Process(['ls', '-lsa']);
$process->start();
// ...
$process->stop(3, SIGINT);

return 0;
}
}

Désormais, vous pouvez exécuter des sous process avec le composant Process de Symfony. Cela dépanne bien lorsqu’il faut automatiser avec des scripts pythons ou autre.

N’hésitez pas à suivre la documentation officielle de Symfony, pour plus d’information.

Publié à l’origine sur https://blog.gary-houbre.fr le 21 Avril, 2021.

--

--

Gary Houbre
Gary Houbre

Written by Gary Houbre

Développeur web depuis 7 ans, je me suis spécialisé sur le développement web avec le language PHP et les framework Symfony et Laravel.

No responses yet