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 Wink.

 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 :

img29Je 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 Wink.

  1. 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…

    • Author bestmomo

      Bonjour,

      Pour répondre il faudrait un peu plus d’informations sur le souci.

  2. Jean Bernard MARCELLUS

    pouvez-vous m’aider a traduire cette ligne de code suivant en blade

    ?

  3. 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 ?

    • Author 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 = "< ?php break; ?>";
      return str_replace("@break", $html, $view);
      });
      Route::get('/', function() {
      return View::make('test');
      });

      Je dis de remplacer @break par < ?php break; ?> 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 :

      < ?php for ($i = 0; $i < 10; $i++): ?>
      < ?php if ($i > 5): ?>
      < ?php break; ?>
      < ?php endif; ?>
      Valeur actuelle : < ?php echo $i; ?>
      < ?php endfor; ?>

      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< ?php $2; ?>$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é.

  4. 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 ?

    • Author 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.

  5. christoff

    Un truc à savoir.
    Si @extends(‘mon_template’) n’est pas sur la première ligne, cela ne fonctionne pas.

  6. thetis

    Dans mon message initial, avec le formatage on lit plus : un(e) « balise div fermante » opheline…

  7. 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 !

  8. 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 ?

    • Author 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é.

Laisser un commentaire