Laravel 4 : chapitre 8 : Blade
Mis à jour avec Bootstrap 3.
Pour le moment nous avons utilisé du PHP pur dans nos vues pour générer le code HTML qui va bien. C’est une méthode simple et efficace mais certains lui reprochent sa lourdeur syntaxique. On peut aussi arguer du fait que PHP a après tout été conçu à la base pour ça et qu’il le fait très bien avec des performances louables. Pour ceux qui s’en contentent c’est parfait, pour les autres des moteurs de template ont été créés. Laravel n’échappe pas à la règle et propose aussi son moteur : Blade. Je vous propose de le découvrir aujourd’hui.
Syntaxe de base
Lorsqu’on veut insérer une donnée avec PHP on utilise cette syntaxe :
<?php echo $valeur ; ?>
On peut aussi utiliser la syntaxe courte (avec PHP 5.4 ou si short_open_tag est activé) :
<?= $valeur ?>
Avec Blade on a cette syntaxe :
{{ $valeur }}
Blade va gentiment transformer ça en :
<?php echo $valeur ; ?>
Pour « échapper » (application de htmlentities) le texte il faut utiliser la triple accolade (il y a eu de chaudes discussions sur les forums pour définir cela) :
{{{ $valeur }}}
Les conditions
Heureusement Blade ne s’arrête pas à cette substitution. Il permet aussi de simplifier l’écriture de conditions. Prenons le cas très fréquent du foreach. Créez une vue avec ce code, nommez-la conditions :
<?php foreach($data as $element) { echo $element.'<br>'; } ?>
Créez cette route :
Route::get('/', function() { $data = array('un','deux','trois','quatre'); return View::make('conditions')->with('data', $data); });
Si vous entrez l’URL http://localhost/laravel/public/ vous devez voir s’afficher :
un
deux
trois
quatre
Voyons l’équivalent avec Blade. Renommez votre vue conditions.blade.php et entrez ce code :
@foreach ($data as $element) {{ $element }}<br> @endforeach
Normalement vous devez obtenir le même résultat. Voyons d’autres syntaxes maintenant que vous avez compris le principe. Remplacez le code de la vue avec celui-ci :
@for ($i =0; $i < count($data); $i++) {{ $data[$i] }}<br> @endfor
Le résultat est évidemment le même. Entrez maintenant ce code :
@foreach ($data as $element) @if ($element == 'un') <p>Je suis le premier et je suis {{$element}} !</p> @else <p>Je ne suis pas le premier et je suis {{$element}} !</p> @endif @endforeach
Cette fois le résultat est :
Je suis le premier et je suis un !
Je ne suis pas le premier et je suis deux !
Je ne suis pas le premier et je suis trois !
Je ne suis pas le premier et je suis quatre !
Je pense que vous avez compris le principe .
Mise en page
Tout cela est déjà bien pratique et rend notre code plus propre. Mais Blade va encore plus loin en nous proposant de puissantes possibilités de mise en page. Prenons un exemple pour voir ça. Créez une vue app/view/mon_template.blade.php avec ce code :
<html> <body> <h1>@yield('titre')</h1> @section('contenu') <p>Contenu principal.</p> @show </body> </html>
Créez une seconde vue app/view/page.blade.php avec ce code :
@extends('mon_template') @section('titre') Mon titre @stop @section('contenu') @parent <p>Contenu de la page</p> @stop
Créez enfin cette route :
Route::get('/', function() { return View::make('page'); });
Si vous entrez l’URL http://localhost/laravel/public/ vous obtenez :
Je suppose que ce simple exemple vous a montré le principe. On crée un template avec du code HTML et deux catégories de champs : @yield pour réserver la place pour une information et @section pour quelque chose de plus fourni avec une information déjà présente. Attention à la syntaxe ! La section se termine par @show.
Pour utiliser le template on doit d’abord le référencer avec @extends. Ensuite on référence les zones réservées avec @section. Et cette fois une section se clôt avec @stop. On inclut le contenu parent avec @parent. On peut ainsi constituer facilement des pages complexes.
Un exemple
Je vais prendre le même exemple que celui du fil précédent avec un site statique mais cette fois en utilisant Blade. Voilà le template que vous appelez template_page.blade.php :
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="utf-8"> <title>Mon beau site</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <link href="assets/css/main.css" rel="stylesheet" type="text/css"> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <header class="jumbotron"> <h1>Mon beau site !</h1> </header> <div class="navbar navbar-default"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Mon beau site</a> </div> <div class="collapse navbar-collapse"> <ul class="nav navbar-nav"> @for ($i = 0; $i < count($data['menu']); $i++) <li{{ ($i == $data['page'])? ' class="active"': ''; }}><a href="{{ $i }}">{{ $data['menu'][$i] }}</a></li> @endfor </ul> </div> </div> <div class="col-md-12"> @yield('content') </div> <hr> <footer class="col-md-12" id="bas"> © Mon beau site... </footer> </div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js"></script> </body>
Je me suis contenté d’utiliser la syntaxe de Blade pour générer le menu et j’ai créé une section pour le contenu. Maintenant il faut modifier les pages en les nommant page0.blade.php, page1.blade.php, page2.blade.php et page3.blade.php :
@extends('template_page') @section('content') Contenu de l'accueil @stop
@extends('template_page') @section('content') Contenu de la page 1 @stop
@extends('template_page') @section('content') Contenu de la page 2 @stop
@extends('template_page') @section('content') Contenu de la page 3 @stop
Et enfin la route :
Route::get('/{page?}', function($page = 0) { $data = array( 'menu' => array('Accueil','Page1','Page2','Page3'), 'page' => $page ); return View::make('page'.$page)->with('data', $data); })->where('page', '[0-3]'); App::missing(function($exception) { return 'Oups ! Je ne connais pas cette page !'; });
Je rappelle aussi le contenu du fichier CSS :
@charset "utf-8"; body { padding-top: 20px; min-height: 2000px; color: #252; } body, .jumbotron, .navbar { background: -moz-radial-gradient(top left, rgba(0,160,0,.5), rgba(0,240,0,0)); background: -webkit-radial-gradient(top left, rgba(0,0,255,.5), rgba(0,240,0,0)); background: -ms-radial-gradient(top left, rgba(0,160,0,.5), rgba(0,240,0,0)); background: -o-radial-gradient(top left, rgba(0,160,0,.5), rgba(0,240,0,0)); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#8383FF', endColorstr='#D8D8FF', GradientType=0); background: radial-gradient(top left, rgba(0,160,0,.5), rgba(0,240,0,0)); } #bas { text-align: center; } p { text-align: justify; } .jumbotron { padding: 30px; border-radius:20px; color:#90d; text-shadow: 0 2px 0 #FFFFFF; } .jumbotron p { text-shadow: 0 1px 0 #FFFFFF; } .jumbotron, .navbar { box-shadow: 3px 3px 3px #059; } .navbar .nav > li > a { color: #90d; font-size: 16px; } .navbar .nav > .active > a, .navbar .nav > .active > a:hover, .navbar .nav > .active > a:focus { background-color: #4c4; box-shadow: 1px 1px 1px 1px #059; }
La syntaxe est bien plus simple avec Blade .
15 commentaires
Jean Bernard MARCELLUS
bonjour est-ce quelqu’un peut m’aider a resourdre ce probleme
quand je developpe le fichier main.blade.php ne prend pas en compte les dossiers contenant des fichiers css, boostrap, js ext…
merci d’avance…
bestmomo
Bonjour,
Pour répondre il faudrait un peu plus d’informations sur le souci.
Jean Bernard MARCELLUS
pouvez-vous m’aider a traduire cette ligne de code suivant en blade
?
Fractaliste
Bonjour,
Tu sais si c’est possible d’étendre les fonctionnalité de Blade ? Par exemple si je veux rajouter un @continue ou un @break ?
bestmomo
Salut !
Pour étendre les fonctionnalités de Laravel c’est pas compliqué, tout est prévu 😉
Pour ton cas je vais prendre l’exemple du break, je mets ça dans les routes :
Blade::extend(function ($view) {
$html = "";
return str_replace("@break", $html, $view);
});
Route::get('/', function() {
return View::make('test');
});
Je dis de remplacer @break par dans les fichiers de Blade.
Voici une vue Blade pour tester :
@for ($i = 0; $i < 10; $i++) @if ($i > 5)
@break
@endif
Valeur actuelle : {{ $i }}
@endfor
Avec comme résultat à la sortie :
Valeur actuelle : 0 Valeur actuelle : 1 Valeur actuelle : 2 Valeur actuelle : 3 Valeur actuelle : 4 Valeur actuelle : 5
Si on va voir ce qui est généré par Blade on trouve ça :
5): ?>
Valeur actuelle :
Bon c’est sommaire mais ça te montre le principe de l’extension qui reste le même pour toutes les classes de Laravel.
Tu peux évidemment améliorer le code, par exemple si tu veux traiter break et continue de façon groupée :
Blade::extend(function($view)
{
return preg_replace('/(\s*)@(break|continue)(\s*)/', '$1$3', $view);
});
Pour l’exemple j’ai mis le code dans le fichier des routes mais ce n’est certainement pas le meilleur endroit pour le faire. En fonction du contexte global de ton application il faut trouver l’emplacement le plus adapté.
christoff
Bonjour,
Je ne sais pas quelle est la bonne méthode pour organiser mes templates.
J’ai d’abord voulu utiliser l’instruction @INCLUDE pour encapsuler trois niveaux :
LA PAGE : qui contient l’entête et le pied de page
LE CORPS : qui est la partie centrale de la page et qui est composé de sections
LA SECTION : qui peut être des articles ou des éléments de navigations par exemple
Ensuite j’ai utilisé l’instruction @EXTENDS pour séparer le contenu et le récipient :
LE CONTENU : qui contient majoritairement des instructions pour le moteur de template et quelques tags html insérés dans des boucles
LE RECIPIENT : qui contient majoritairement des tags html qui peuvent être nombreux quand on utilise un framework css, et quelques instructions du moteur de template comme @YIELD
Je pouvais donc avoir 6 documents différents, et lorsque j’ai voulu passer à la pratique je me suis rendu compte que le nombre de fichier pouvait être très important. Pensant que ma méthode n’était pas bonne, j’ai cherché des informations sur le net et je n’ai trouvé aucun tutoriel sur le sujet. J’ai finalement opté pour 4 types de documents :
Le Make::View de mon contrôleur pointe vers un Contenu de page
Le contenu de page @extends vers un récipient de page et @include des contenus de section
Chaque contenu de section @extends vers un récipient de section
Existe-t-il une règle de l’art en la matière ou bien est-ce que je me prends trop la tête ?
bestmomo
Blade est suffisamment souple pour s’adapter à toutes les situations. Je n’ai jamais trouvé non plus de guide de bonne pratique à ce sujet. Viser le moins de fichiers possible me semble être une bonne optique.
christoff
Un truc à savoir.
Si @extends(‘mon_template’) n’est pas sur la première ligne, cela ne fonctionne pas.
bestmomo
Oui effectivement elle div…ague cette balise 😉 merci
thetis
Dans mon message initial, avec le formatage on lit plus : un(e) « balise div fermante » opheline…
thetis
Un minuscule détail. Dans app/view/mon_template.blade.php, il ya un orphelin et me semble -t-il inutile… Excellent blog pour autant !
Juli3nG
Bonjour, je rencontre un petit problème avec Blade.
J’ai réussi à créer mon template (parent puis enfant), cependant lorsque j’effectue une modification sur l’un des deux, l’affichage ne se met pas à jour. J’ai repéré qu’il y avait un système de cache pour les templates, comment le forcer à se recréer ?
bestmomo
Bonjour,
Je n’ai encore jamais rencontré ce problème. Les vues sont créées et stockées dans le dossier app/storage/views, mais elles sont récréées à chaque fois. Ce ne serait pas plutôt le cache du navigateur ?
Juli3nG
Ça ne vient pas du cache, je le vide à chaque actualisation… Je vais réessayer, mais pour le moment le seul moyen de mettre à jour mes templates est de vider le dossier app/storage/views. Les fichiers temporaires sont bien déposés dedans, donc je ne pense pas non plus que ce soit un problème de droit. Merci de ta réponse en tout cas, je reviens vers toi si je n’avance pas. 😉
Juli3nG
Ça y est ça marche !
Pour la petite explication, mon serveur n’était pas à l’heure, du coup les vues générées en cache étaient dans le futur. Sachant que laravel regarde l’heure de modification de la vue, il ne la mettait pas à jour. Après resynchro du serveur ça marche du tonnerre.
Merci encore pour le temps que tu m’as consacré.