Je suis développeur web freelance et propose des formations à Symfony2 ! Contactez-moi pour en discuter.

Cet article est la traduction d’un article original de Fabien Potencier, à l’origine de Symfony2, disponible ici.

Jusqu’à présent, notre application était très simple car il n’y a qu’une seule page. Pour la rendre plus sympa, soyons fous et ajoutons une nouvelle page pour dire au revoir :


send();

Comme vous pouvez le voir, la plupart du code est exactement le même que celui que nous avons écrit pour la première page. Commençons par extraire le code commun, partagé entre toutes les pages. Le partage de code semble une bonne idée pour créer notre premier « vrai » framework !

Pour effectuer ce refactoring en PHP, on peut se servir de la création d’un fichier à inclure :


Voici ceci dans le contexte :


get('name', 'World');

$response->setContent(sprintf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8')));
$response->send();

Quand à la page "Au revoir" :


setContent('Goodbye!');
$response->send();

Nous avons effectivement déplacé la plupart du code partagé à un endroit central, mais cela ne semble pas être une très bonne abstraction, pas vrai ? Tout d'abord, nous avons la méthode send() dans toutes les pages, nos pages ne ressemble pas à des templates et nous ne sommes toujours pas capable de tester ce code proprement.

De plus, ajouter une nouvelle page signifie que nous devons créer un nouveau script PHP, dont le nom est disponible à l'utilisateur via l'URL (http://example.com/bye.php): il y a un lien direct entre le nom du script PHP et l'URL client, car c'est le serveur qui s'occupe de dispatcher les requêtes directement... Cela peut être une bonne idée de nous occuper nous même de cela pour une meilleure flexibilité. Cela peut être réalisé facilement en routant toutes nos requêtes client vers un unique script PHP.

Fournir un unique script PHP à l'utilisateur est un design pattern qui s'appelle "le controlleur de façade".

Un tel script pourrait ressembler à celà :


__DIR__.'/hello.php',
'/bye' => __DIR__.'/bye.php',
);

$path = $request->getPathInfo();
if (isset($map[$path])) {
require $map[$path];
} else {
$response->setStatusCode(404);
$response->setContent('Not Found');
}

$response->send();

Et voila le contenu du nouveau script hello.php :


get('name', 'World');
$response->setContent(sprintf('Hello %s', htmlspecialchars($input, ENT_QUOTES, 'UTF-8')));

Dans le script front.php, $map associe le chemin de l'URL avec les chemins des scripts PHP correspondants.

En bonus, si le client demande un chemin qui n'est pas défini dans cette table de hashage, nous renvoyions une erreur 404 custom; vous avez maintenant le controle de votre site web.

Pour accéder à une page, vous devez maintenant utiliser le script front.php :

  • http://example.com/front.php/hello?name=Fabien
  • http://example.com/front.php/bye

/hello et /bye sont les chemins des pages.

La plupart des serveurs web tel que Apache ou nginx sont capables de réécrire l'URL d'entrée et enlever le script du controlleur de façade de telle sorte que les utilisateurs puissent taper http://example.com/hello?name=Fabien, qui est bien plus jolie.

L'astuce réside donc dans l'utilisation de la méthode Request::getPathInfo() qui renvoie le chemin de la requête en supprimant le nom du script du controlleur de façade, y compris les sous répertoires (si nécessaire)

Vous n'avez même pas besoin de mettre en place un serveur web pour tester le code. A la place, remplacez l'appel à $request = Request::createFromGlobals(); par quelque chose comme $request = Request::create('/hello?name=Fabien'); où l'argument est le chemin d'URL que vous voulez simuler.

Maintenant que le serveur web accède toujours au même script (front.php) pour toutes les pages, nous pouvons sécuriser le code un peu plus en déplace tous les autres fichiers PHP à l'extérieur de la racine du répertoire web :


example.com
+-- composer.json
¦ src
¦ +-- autoload.php
¦ +-- pages
¦ +-- hello.php
¦ +-- bye.php
+-- vendor
+-- web
+-- front.php

Maintenant, configurez la racine de votre serveur web pour pointer sur web/ et tous les autres fichiers ne seront plus accessibles.

Pour que cette structure fonctionne, vous devrez ajuster certains chemins dans les divers fichiers PHP; ces changement sont laissés en exercice au lecteur.

La dernière chose qui est répétée dans toutes les pages, c'est l'appel à setContent(). Nous pouvons convertir toutes les pages en des templates en faisant des "echo" du contenu à afficher, et en appellant setContent() directement depuis le script du controleur de façade :


getPathInfo();
if (isset($map[$path])) {
ob_start();
include $map[$path];
$response->setContent(ob_get_clean());
} else {
$response->setStatusCode(404);
$response->setContent('Not Found');
}

// ...

Et le script hello.php peut être transformé en un template :

get('name', 'World') ?>

Hello

Nous avons notre framework du jour :


__DIR__.'/../src/pages/hello.php',
'/bye' => __DIR__.'/../src/pages/bye.php',
);

$path = $request->getPathInfo();
if (isset($map[$path])) {
ob_start();
include $map[$path];
$response->setContent(ob_get_clean());
} else {
$response->setStatusCode(404);
$response->setContent('Not Found');
}

$response->send();

Ajouter une nouvelle page se fait en 2 étapes : ajouter une entrée dans la map et créer un template PHP dans ``src/pages/``. Depuis un template, on obtient les données de la requête via la variable $request et on fournit une réponse adaptée via la variable $response.

Si vous décidez de vous arrêter là, vous pouvez probablement améliorer votre framework entre extrayant la liste des URL depuis un fichier de configuration

Répondre

Unable to load the Are You a Human PlayThru™. Please contact the site owner to report the problem.