Allez plus loin avec le microframework Silex

logo_silex

Nous avons vu dans un précédent article les bases du framework Silex, son installation, son utilisation très basique.

Cet article permettra d’aborder un peu plus en détails certaines possibilités qu’offrent ce framework et de voir  comment découper notre code car l’idée n’est pas d’avoir tout dans un même fichier.

Pour nous remettre dans le contexte notre architecture de dossier était le suivant pour l’instant :

app/

src/

web/

Nous avions créé un fichier index.php avec le code suivant qui permettait d’afficher Hello Prénom en tapant l’url index.php/hello/Marc :

<?php
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
$app->register(new Silex\Provider\TwigServiceProvider(), array(

   'twig.path' => dirname(__DIR__) . "/CHEMIN_HTML",

));
$app->get('/', function () {
    return 'Hello world';
});
$app->run();
?>

Avant d’aller plus loin nous allons créer un fichier bootstrap qui va s’occuper d’enregistrer tous nos services dans notre application puis de lancer notre application.

Notre fichier index.php se contentera uniquement d’inclure le fichier bootstrap.php. Nous avons donc pour le fichier index.php :

<?php
require_once __DIR__ . '/../app/bootstrap.php';
?>

 

Pour le fichier bootstrap.php :

<?php
$app = new Silex\Application();
$app->get('/', function () {
    return 'Hello world';
});
$app->run();
?>

 

Fournisseur de controller (Controller Provider)

Chaque application se doit d’avoir une organisation logique du code. Avoir tout le code dans un seul fichier ne répond pas à cette logique. Nous allons donc découpler notre code afin d’avoir plusieurs controllers.

C’est là qu’entre en jeu le fournisseur de controller.

Chaque controller implémentera l’interface ControllerProviderInterface où l’on devra définir la function connect.

Cette function sera notre point d’entrée pour chaque controller.

Silex met à disposition un gestionnaire de controller grâce à $app['controllers_factory'] qui retourne une instance de Silex\ControllerCollection.

Nous allons créer dans app/ un dossier Controller qui contiendra tous nos controllers.

Créons notre fichier indexController.php

<?php
namespace app\Controller;
use Silex\Application;
use Silex\ControllerProviderInterface;

class IndexController implements ControllerProviderInterface
{
public function connect(Application $app)
 {
        // code à executer a chaque entrée du controller
 }
?>

 

Réorganisation de nos routes

Nous avons jusqu’à présent pour chaque route, défini du code à exécuter grâce à une closure.

Voyons ensemble une autre manière de faire :

Nous allons maintenant définir nos routes dans chaque controller dans notre fonction connect vu plus  haut :

Pour reprendre notre exemple de route qui permettait d’afficher notre Hello Prénom nous aurons donc :

public function connect(Application $app)
 {
       $controllers = $this->app['controllers_factory'];

       $controllers->get('/hello/{nom}', [$this, 'index'])->bind('accueil');
        return $controllers;
 }

public function index($nom){
    return “Hello $name”;
}

$controllers->get('/hello/{id}', [$this, 'index'])->bind('accueil') :  nous avons notre route à intercepter, en 2ème argument la fonction contenant le code à exécuter. Noter la function bind qui permet de nommer nos routes afin de les utiliser pour nos urls.

Reste une dernière étape, prévenir notre application de prendre en compte nos controllers et donc de nos routes aussi.

Nous allons rajouter dans notre fichier bootstrap de code avant notre $app->run().

$app->mount("/", new app\Controller\IndexController());

Cette function mount permet de préfixer nos routes. Ainsi on retrouvera tout notre code concernant notre page index.

Il suffira de rajouter pour chaque controller :

$app->mount("/", new app\Controller\NOTRE_CONTROLLER);

Pensez au découplage du code.

 

Quelques fonctions utiles

Toujours en relation avec le routing, Silex nous permet la conversion des variables passées dans nos routes.

Voyons ensemble un exemple dans notre fichier indexControlller.php

<?php
//----------
$controllers->get('/client/{id}', [$this, 'index'])->convert($id, [$this, 'utilisateur'])->bind('accueil')
//----------

public function index($id){
  //code a executer
}

public function utilisateur($id){
/*recherche en bdd l’existence de cet id avec retour du résultat dans $userFind d’un object correspondant à l’utilisateur si celui-ci existe bien
*/
if(count($userFin) == 0){
 throw new exception("Utilisateur inxistant");
}
else {
 return $userFind[0];
}
}
?>

Expliquons ce que nous venons de faire :

A chaque fois que nous demanderons l’url /client/7, avant d’exécuter la fonction index on demande de convertir (exécuter le code avec la fonction utilisateur ) notre id en objet utilisateur. Dans cet exemple si l’utilisateur existe nous exécutons alors le code de la fonction index où l’id en paramètre sera donc l’objet retourné par la fonction utilisateur.

Ce système de conversion peut bien être utilisé par plusieurs routes qui nécessitent de récupérer un objet utilisateur afin de vérifier si l’id correspond bien à un utilisateur dans notre bdd, ce qui peut être très pratique au cas où l’on passera un id arbitraire.

 

Étudions un autre concept qu’offre le framework Silex, le système de « déclencheur de code » à un moment précis.

Imaginons nous voulons exécuter du code uniquement si un utilisateur est connecté. A chaque connexion nous créons une session utilisateur.

Afin de pouvoir faire cela before va faire son entrée en jeu.

Reprenons notre exemple :

<?php
public function connect(Application $app)
{
    $app->before(function(){
     if($this->app['session']->get('user') === null){
             $app->redirect(URL_PAGE_LOGIN);
     }
   });
    $controllers = $this->app['controllers_factory'];
    $controllers->get('/hello/{nom}', [$this, 'index'])->bind('accueil');
    return $controllers;
}
?>

Avant l’exécution de notre controller on intercepte la requête en vérifiant l’existence de la session utilisateur. Si inexistante on redirige vers la page login.

On a le même principe après l’exécution du controller avec $app->after(), nous avons également $app->finish() qui permet d’exécuter du code une fois la réponse retournée.

 

J’espère que toutes ces explications vous ont permis d’aller plus loin avec le framework Silex.

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *