Retour sur le Forum PHP 2024
Découvrez un résumé concis des conférences qui nous ont le plus marqué lors du Forum PHP 2024 !
Lorsque l’on développe un site, en particulier un site à fort trafic, on est forcément amené à se poser la question des ressources consommées par ce dernier afin d’optimiser son temps de réponse. En effet, une page qui met plus de 3-4 secondes à s’afficher rend vite désagréable la navigation et découragera plus d’une personne à venir sur votre site.
Le système de cache de Symfony vous permettra de diminuer les temps de réponses de vos pages en utilisant la puissance du cache HTTP tel qu'il est défini dans la spécification HTTP. Sachez cependant que ce n’est qu’une des solutions possibles.
Pour augmenter la vitesse d'une application, on peut par exemple:
Pour revenir au cache http, expliquons en un peu le principe. Le rôle de la mémoire cache (ou reverse proxy) est d’accepter les requêtes coté client et de les transmettre au serveur. Il va ensuite recevoir les réponses et les transmettre au client. Lors de ces deux étapes, il va mémoriser les requêtes et les réponses associées. Ceci lui permettra lorsque qu’une même requête est demandée, de vous retourner la réponse sans la redemander au serveur. On économise donc du temps et des ressources.
Rentrons maintenant dans le vif du sujet. Symfony est équipé d’un reverse proxy défini par la classe AppCache.php qui se situe dans app/AppCache.php de votre projet.
Sa mise en place dans Symfony est relativement simple.
Il vous faut dans un premier temps modifier votre app_dev.php afin qu’il ressemble à ceci :
<?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Debug\Debug; // If you don't want to setup permissions the proper way, just uncomment the following PHP line // read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information //umask(0000); // This check prevents access to debug front controllers that are deployed by accident to production servers. // Feel free to remove this, extend it, or make something more sophisticated. if (isset($_SERVER['HTTP_CLIENT_IP']) || isset($_SERVER['HTTP_X_FORWARDED_FOR']) || !in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) ) { header('HTTP/1.0 403 Forbidden'); exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); } $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; Debug::enable(); require_once __DIR__.'/../app/AppKernel.php'; require_once __DIR__.'/../app/AppCache.php'; $kernel = new AppKernel('dev', true); $kernel->loadClassCache(); $kernel = new AppCache($kernel); Request::enableHttpMethodParameterOverride(); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response);
Et c’est tout? Eh ben oui, c’est pas plus compliqué que ça. Rajoutez votre dépendance à AppCache et instanciez là avec en paramètre votre kernel.
Maintenant, on va dans un premier temps créer un exemple sans activer le cache.
Pour le routing:
#app/config/routing.yml cache: resource: "@MyBundle/Resources/config/routing.yml" prefix: /
MyBundle/Ressources/config/routing.yml:
example: pattern: /example defaults: { _controller: MyBundle:Example:cache}
Voici pour le Controller:
<?php
namespace MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ExampleController extends Controller {
public function cacheAction() {
return $this->renderView('MyBundle:Cache:cache.html.twig', array('hello' => 'Hello World!!!'));
}
}
Enfin, votre template cache.html.twig situé dans MyBundle/Resources/views/Cache/cache.html.twig:
{% extends "@MyBundle/layout.html.twig" %}
{% block body %}
<h1>{{ hello }}</h1>
{% endblock %}
Et voilà le résultat:
Maintenant pour s’assurer que le cache est bien inactif, ouvrez firebug.
Allez dans l’onglet Réseau (ou Network pour ceux qu’ils l’ont en anglais),
Et dépliez le get correspondant à votre route:
On voit donc bien ici la valeur du Cache-Control qui est à no-cache.
Maintenant pour activer le cache, on va légèrement modifier notre Controller. Commencez par rajouter votre dépendance à l’objet Response dans votre controller:
use Symfony\Component\HttpFoundation\Response;
Modifiez maintenant votre action:
public function cacheAction() {
$response = new Response();
$response->setMaxAge(300);
// Check that the Response is not modified for the given Request
if (!$response->isNotModified($this->getRequest())) {
$date = new \DateTime();
$response->setLastModified($date);
$response->setContent($this->renderView('MyBundle:Cache:cache.html.twig', array('hello' => 'Hello World!!!')));
}
return $response;
}
}
Voici une utilisation très simpliste du système de cache.
L’objet Response va nous permettre de manipuler les différents éléments d’information de l’en-tête Cache-Control. Ici, je me suis contenté de définir le temps de validité de la réponse mise en cache (ici 300 secondes). Au-delà de cette durée, la réponse va être régénérée par le serveur et sera de nouveau valide durant 300 secondes. Si la réponse est encore valide, on la retourne directement sinon on régénère la réponse et on modifie sa date de modification.
Maintenant, si on jette à nouveau un œil à notre firebug:
On constate que le système de cache est bien activé. Pour aller plus loin avec les différentes options possibles de l’en-tête, je vous invite fortement, si ce n’est pas déjà fait, à lire la doc sur le site officiel de Symfony.
Ok, tout ça c’est bien, mais cela met en cache une page entière. Mais votre besoin sera peut-être de ne mettre en page qu’une partie de la page. Heureusement pour nous, Symfony a pensé à tout et nous fournit une solution, les «Edge Side Includes» (ESI).
Pour activer le mode ESI dans Symfony, ouvrez votre app/config/config.yml et ajoutez ces deux lignes dans la partie framework :
framework: esi: { enabled: true }
Maintenant créez un deuxième template. Moi je l’appellerai esi.html.twig et il contiendra simplement:
<h2>Partie en Cache</h2>
Modifiez le premier template:
{% extends "@ MyBundle/layout.html.twig" %}
{% block body %}
<h1>{{ hello }}</h1>
{{ render_esi(controller(' MyBundle:Example:getEsiCache')) }}
{% endblock %}
Et enfin votre controlleur:
<?php
namespace My\Bundle\TrainingBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class ExampleController extends Controller {
public function cacheAction() {
return $this->render('MyBundle:Cache:cache.html.twig',
array('hello' => 'Hello World!!!'));
}
public function getEsiCacheAction(Request $request) {
$response = new Response();
$response->setSharedMaxAge(10);
$response->setPublic();
$response->setMaxAge(10);
// Check that the Response is not modified for the given Request
if (!$response->isNotModified($request)) {
$date = new \DateTime();
$response->setLastModified($date);
$response->setContent($this->renderView('MyBundle:Cache:esi.html.twig'));
}
return $response;
}
}
J’ai ici simplifié l’action cacheAction() pour n’activer le cache que pour le fragment ESI.
Actualiser votre page et vous devez obtenir ceci:
Maintenant, si on repart voir ce que nous dit notre bon vieil ami firebug, on voit:
Une ligne X-Symfony-Cache est apparu. Si on se concentre sur la fin de la ligne, on lit: «…EsiCache: stale, invalid, store». En gros, le cache de ce fragment n’était pas valide (normal vu qu’on vient de le créer :) ). Mais si vous faite un petit F5, vous aurez le message suivant:
Aahhhh, ça a l’air d’être «fresh» :)
Je vous passe les explications mais vous aurez compris que le fragment en cache était valide et qu’il a pu être retourné directement.
Vous avez maintenant les bases pour voler de vos propres ailes et optimiser votre application.
Auteur(s)
Cédric Moncade
Développeur PHP/Symfony depuis maintenant 4 ans, je m'interresse aux nouvelles technologies et en tant qu'Astronaute, conquérir de nouveaux bars.
Vous souhaitez en savoir plus sur le sujet ?
Organisons un échange !
Notre équipe d'experts répond à toutes vos questions.
Nous contacterDécouvrez nos autres contenus dans le même thème
Découvrez un résumé concis des conférences qui nous ont le plus marqué lors du Forum PHP 2024 !
Le composant Symfony ExpressionLanguage : qu'est-ce que c'est ? Quand et comment l'utiliser ? Comment créer des expressions lors de cas plus complexes ?
Découvrez comment réaliser du typage générique en PHP : introduction et définition du concept, conseils et explications pas-à-pas de cas pratique.