IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tutoriel pour apprendre à utiliser le framework Laravel 4


précédentsommairesuivant

XXVII. Chapitre 27 : Cache et configuration

Voyons aujourd'hui la mise en cache à la sauce Laravel 4. Je rappelle qu'un cache est destiné à accélérer la génération des pages en gardant en mémoire des informations. Le cas le plus classique est celui de requêtes sur une base de données. Si les données ne changent pas fréquemment il est plus efficace de mettre en cache leur résultat plutôt que d'aller chaque fois interroger la base. On peut aussi carrément mettre en cache des pages complètes.

Laravel 4 propose un système de cache simple et efficace qui mémorise par défaut les informations dans un fichier. Regardez le fichier app/config/cache.php :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
return array(
 
    /*
    |--------------------------------------------------------------------------
    | Default Cache Driver
    |--------------------------------------------------------------------------
    |
    | This option controls the default cache "driver" that will be used when
    | using the Caching library. Of course, you may use other drivers any
    | time you wish. This is the default when another is not specified.
    |
    | Supported: "file", "database", "apc", "memcached", "redis", "array"
    |
    */
 
    'driver' => 'file',
 
    /*
    |--------------------------------------------------------------------------
    | File Cache Location
    |--------------------------------------------------------------------------
    |
    | When using the "file" cache driver, we need a location where the cache
    | files may be stored. A sensible default has been specified, but you
    | are free to change it to any other place on disk that you desire.
    |
    */
 
    'path' => storage_path().'/cache',
 
    /*
    |--------------------------------------------------------------------------
    | Database Cache Connection
    |--------------------------------------------------------------------------
    |
    | When using the "database" cache driver you may specify the connection
    | that should be used to store the cached items. When this option is
    | null the default database connection will be utilized for cache.
    |
    */
 
    'connection' => null,
 
    /*
    |--------------------------------------------------------------------------
    | Database Cache Table
    |--------------------------------------------------------------------------
    |
    | When using the "database" cache driver we need to know the table that
    | should be used to store the cached items. A default table name has
    | been provided but you're free to change it however you deem fit.
    |
    */
 
    'table' => 'cache',
 
    /*
    |--------------------------------------------------------------------------
    | Memcached Servers
    |--------------------------------------------------------------------------
    |
    | Now you may specify an array of your Memcached servers that should be
    | used when utilizing the Memcached cache driver. All of the servers
    | should contain a value for "host", "port", and "weight" options.
    |
    */
 
    'memcached' => array(
 
        array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
 
    ),
 
    /*
    |--------------------------------------------------------------------------
    | Cache Key Prefix
    |--------------------------------------------------------------------------
    |
    | When utilizing a RAM based store such as APC or Memcached, there might
    | be other applications utilizing the same cache. So, we'll specify a
    | value to get prefixed to all our keys so we can avoid collisions.
    |
    */
 
    'prefix' => 'laravel',
 
);

Vous trouvez toutes les possibilités de configuration du cache. Vous voyez en premier la façon dont les informations sont stockées :

  • fichier (valeur par défaut) ;
  • base de données ;
  • APC ;
  • Memcached ;
  • Redis ;
  • array.

Vous trouvez aussi la localisation du fichier (par défaut app/storage/cache) ; ainsi que : le nom de la base et de la table à utiliser dans le cas de stockage en base de données, le paramétrage de memcached, ; le préfixe pour APC ou Memcached.

Quelle que soit la méthode choisie, la classe Cache de Laravel offre les mêmes possibilités de base.

XXVII-A. Les commandes de base

Avec une nouvelle installation de Laravel 4 entrez ce code dans le fichier des routes :

 
Sélectionnez
1.
2.
3.
4.
5.
Route::get('/', function()
{
    Cache::put('un', '1', 2);
    echo Cache::get('un');
});

Résultat :

 
Sélectionnez
1

La méthode put permet de mémoriser une information : le premier paramètre est la clé, le second la valeur et le troisième la durée de conservation de l'information.

La méthode get est l'inverse, et permet de retrouver une information mémorisée à partir de sa clé.

Regardons maintenant le fichier créé :

Image non disponible

Et son contenu :

 
Sélectionnez
1368103994s:1:"1";

Il est possible de conserver indéfiniment une information en utilisant la méthode forever :

 
Sélectionnez
Cache::forever('un', '1');

Et la méthode forget pour en supprimer une :

 
Sélectionnez
Cache::forget('un');

On a aussi la possibilité d'affecter une valeur par défaut en cas d'inexistence de la valeur :

 
Sélectionnez
Cache::get('deux', function() { return '2'; });

Vous pouvez aussi récupérer une valeur dans le cache et la mémoriser si elle n'est pas présente :

 
Sélectionnez
1.
2.
3.
4.
$value = Cache::remember('un', 1, function()
{
    return 1;
});

XXVII-A-1. Un cas d'application

Voyons maintenant un cas d'application qui justifie l'utilisation d'un cache. Si vous allez sur cette page vous trouvez la documentation de Laravel 4. Cette application a été réalisée par Dayle Rees et le code se trouve ici. Je me suis dit qu'il y avait une façon plus simple de procéder en allant directement chercher les informations sur la page du projet. Surtout qu'il y a une page avec la table des matières.

XXVII-A-1-a. La route

Partez d'une nouvelle installation de Laravel. Dans le fichier des routes mettez juste ce code pour appeler un contrôleur :

 
Sélectionnez
Route::get('/{name?}', 'DocController@show');
XXVII-A-1-b. Le contrôleur

Voici le code du contrôleur app/controllers/DocController.php :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
<?php
 
class DocController extends BaseController {
 
    /**
     * Le template de base
     */
    protected $layout = 'layout.master';
 
    /**
     * Récupération du HTML d'un URL
     */
    private function getHtml($url)
    {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;         
    }
 
    /**
     * Récupération d'une balise dans du HTML
     */
    private function getTag($html, $tag, $exclu = null)
    {
        $start = strpos($html, '<' . $tag);
        $end = strpos($html, '</' . $tag);
        if($exclu == null) {
            return substr($html, $start, $end - $start + strlen($tag) + 2); 
        } else {
            $start = strpos($html, '>', $start) + 1;
            return substr($html, $start, $end - $start);  
        }                 
    }
 
    /**
     * Affichage de la page.
     */
    public function show($name = 'introduction')
    {
        // Récupération de la page d'index
        $index = $this->getHtml('https://github.com/laravel/docs/blob/master/documentation.md');
 
        // Sélection de l'index
        $index = $this->getTag($index, 'article', true); 
 
        // Création du DOM
        libxml_use_internal_errors(true);
        $doc = new DOMDocument;
        $doc->loadHTML($index);
 
        // Changement des liens
        $nodes = $doc->getElementsByTagName('a');
        foreach ($nodes as $node) {
            $link = $node->getAttribute('href');
            $node->setAttribute('href', basename($link));
            $node->setAttribute('class', 'btn btn-small');
        }
 
        // Création du Html élagué
        return $this->getTag($doc->saveHTML(), 'body', true);
 
        // Récupération du contenu
        $content = $this->getHtml('https://github.com/laravel/docs/blob/master/' . $name . '.md');
 
        // Sélection du texte
        $content = $this->getTag($content, 'article');  
 
        // Création du DOM
        $doc->loadHTML($content);
 
        // Ajout de la classe pour le prettify
        $nodes = $doc->getElementsByTagName('pre');
        foreach ($nodes as $node) {
            $node->setAttribute('class', 'prettyprint');
        }  
 
        // Ajout classes pour les tableaux
        $nodes = $doc->getElementsByTagName('table');
        foreach ($nodes as $node) {
            $node->setAttribute('class', 'table table-bordered table-condensed');
        }  
 
        // Création du Html élagué
        $content = $this->getTag($doc->saveHTML(), 'body', true); 
 
        // Affichage de la vue
        $this->layout->content = View::make('main', array('nav' => $nav, 'content' => $content));
    }
 
}

En gros le code permet d'aller récupérer le lien HTML de la documentation, de sélectionner juste ce qui est utile, de modifier les liens et d'ajouter quelques classes pour la présentation. Je laisse des classes devenue inutiles, les puristes peuvent les supprimer…

XXVII-A-1-c. Les vues

Créez le template app/views/layout/master.blade.php :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>Laravel documentation</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  {{ HTML::style('assets/css/bootstrap.min.css') }}
  {{ HTML::style('assets/css/bootstrap-responsive.min.css') }}
  {{ HTML::style('assets/css/main.css') }}
</head>
 
<body>
  <div class="container">
    <h1>Documentation de Laravel 4</h1>
    <hr>
    <div class="row">
      <nav class="span3">
        @yield('navigation')
      </nav>
      <section class="span9">
        @yield('content')
      </section>
    </div>
  </div>
  {{ HTML::script('assets/javascript/run_prettify.js') }}
</body>

On charge Bootstrap pour la mise en forme, on prévoit deux localisations pour la navigation et le contenu et on charge Prettify pour la coloration syntaxique du code.

On crée ensuite la vue app/views/main.blade.php qui utilise ce template :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
@section('navigation')
  {{ $nav }}
@stop
 
@section('content')
  {{ $content }}
@stop
XXVII-A-1-d. Les assets

Il ne nous manque plus que les assets :

Image non disponible

Pour télécharger Bootstrap c'est ici. Et pour Prettify c'est ici. Et voici le code de main.css :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
body {
    background-color: #ccc;
}
.container {
    margin-top: 20px;
}
pre {
    background-color: white;
}
ul {
    list-style-type: none;
}
nav ul:first-child {
    font-size: 20px;
    padding: 10px;
    color: #27a;
}

Et voici l'apparence du résultat :

Image non disponible

Les liens fonctionnent et la présentation est agréable ( à mon goût, mais vous pouvez changer tout ce que vous voulez Image non disponible).

XXVII-A-2. Mise en cache pour l'application

Maintenant que nous avons une application plutôt laborieuse parce qu'elle doit envoyer des requêtes HTTP pour récupérer des informations, nous pouvons utiliser un cache pour la rendre bien plus rapide. Il faut mettre en cache d'une part la table des matières, et ensuite chacun des chapitres au fur et à mesure qu'ils sont affichés. Voici le contrôleur modifié en conséquence :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
class DocController extends BaseController {
 
    /**
     * Le template de base
     */
    protected $layout = 'layout.master';
 
    /**
    * Récupération du HTML d'un URL
    */
    private function getHtml($url)
    {
        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;         
    }
 
    /**
    * Récupération d'une balise dans du HTML
    */
    private function getTag($html, $tag, $exclu = null)
    {
        $start = strpos($html, '<' . $tag);
        $end = strpos($html, '</' . $tag);
        if($exclu == null) {
            return substr($html, $start, $end - $start + strlen($tag) + 2); 
        } else {
            $start = strpos($html, '>', $start) + 1;
            return substr($html, $start, $end - $start);  
        }                 
    }
 
    /**
     * Affichage de la page
     */
    public function show($name = 'introduction')
    {
        // Récupération de l'index
        $nav = Cache::remember('nav', 60, function()
        {
            // Récupération de la page d'index
            $index = $this->getHtml('https://github.com/laravel/docs/blob/master/documentation.md');
 
            // Sélection de l'index
            $index = $this->getTag($index, 'article', true); 
 
            // Création du DOM
            libxml_use_internal_errors(true);
            $doc = new DOMDocument;
            $doc->loadHTML($index);
 
            // Changement des liens
            $nodes = $doc->getElementsByTagName('a');
            foreach ($nodes as $node) {
                $link = $node->getAttribute('href');
                $node->setAttribute('href', basename($link));
                $node->setAttribute('class', 'btn btn-small');
            }
 
            // Création du Html élagué
            return $this->getTag($doc->saveHTML(), 'body', true);
        });
 
        // Récupération du contenu
        $content = Cache::remember($name, 60, function() use ($name)
        {
            $content = $this->getHtml('https://github.com/laravel/docs/blob/master/' . $name . '.md');
 
            // Sélection du texte
            $content = $this->getTag($content, 'article');  
 
            // Création du DOM
            libxml_use_internal_errors(true);
            $doc = new DOMDocument;
            $doc->loadHTML($content);
 
            // Ajout de la classe pour le prettify
            $nodes = $doc->getElementsByTagName('pre');
            foreach ($nodes as $node) {
                $node->setAttribute('class', 'prettyprint');
            }  
 
            // Ajout classes pour les tableaux
            $nodes = $doc->getElementsByTagName('table');
            foreach ($nodes as $node) {
                $node->setAttribute('class', 'table table-bordered table-condensed');
            }  
 
            // Création du Html élagué
            return $this->getTag($doc->saveHTML(), 'body', true); 
        });
 
        // Affichage de la vue
        $this->layout->content = View::make('main', array('nav' => $nav, 'content' => $content));
    }
 
}

Maintenant notre application devient performante. J'ai réglé la durée de mémorisation à 60 minutes, ce qui semble très raisonnable dans ce cas parce que la documentation change rarement.

XXVII-A-3. Configuration

On peut améliorer l'ergonomie de notre application en utilisant un fichier de configuration pour la durée de mémorisation et le titre de la page. Créez un fichier app/config/doc.php avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
return array(
 
/*
|--------------------------------------------------------------------------
| Titre
|--------------------------------------------------------------------------
|
| Titre qui apparaît en haut de la page 
|
| Défaut : 'Documentation de Laravel 4'
|
*/
 
'title' => 'Documentation de Laravel 4',
 
/*
|--------------------------------------------------------------------------
| Durée
|--------------------------------------------------------------------------
|
| Durée de mémorisation pour le cache en minutes
|
| Défaut : 60
|
*/
 
'timer' => 60
 
);

Il ne reste plus qu'à modifier le template app/views/layout/master.blade.php :

 
Sélectionnez
<h1>{{ Config::get('doc.title') }}</h1>

Et le contrôleur :

 
Sélectionnez
$nav = Cache::remember('nav', Config::get('doc.timer'), function()
 
Sélectionnez
$content = Cache::remember($name, Config::get('doc.timer'), function() use ($name)

Les paramètres sont ainsi centralisés dans un fichier dédié Image non disponible.


précédentsommairesuivant

Copyright © 2017 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.