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

Cours pour apprendre à utiliser le framework Laravel 5.5

Plus loin avec Laravel


précédentsommairesuivant

VI. Les vues

Je vous ai déjà parlé des vues dans ce cours, ainsi que de Blade, et on a eu plusieurs exemples de code. Dans ce chapitre je vais faire un peu le point et montrer des possibilités intéressantes qui n'ont pas encore été évoquées.

Dans mes précédents cours, je mettais en avant le package Laravel Collective pour générer le HTML. C'est une possibilité élégante et performante mais j'en suis revenu à du codage standard, surtout au vu des améliorations de Blade. C'est juste une question de choix personnel et je vous invite à essayer le package en question pour voir s'il vous convient.

Les exemples de code de ce chapitre sont issus de cette application d'exemple .

Les vues générées par Blade sont en PHP et sont en cache jusqu'à ce qu'elles soient modifiées, ce qui assure de bonnes performances. Le cache se situe ici :

Image non disponible

Si vous avez besoin de nettoyer ce cache, ce n'est pas la peine d'aller supprimer ces fichiers dans le dossier : il y a une commande Artisan pour ça :

 
Sélectionnez
php artisan view:clear

On en a besoin parfois en cours de développement lorsqu'une vue n'est pas régénérée correctement.

VI-A. L'héritage

On a constaté qu'une vue peut en étendre une autre : c'est un héritage. Ainsi, pour les vues du front, on a un template (layout) de base :

Image non disponible

Ce template comporte la structure globale des pages et est déclaré comme parent par les autres vues :

 
Sélectionnez
@extends('front.layout')

Dans le template on prévoit trois emplacements (@yield) pour que les vues enfants puissent placer leur code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
<!DOCTYPE html>

   @yield('css')

   ...
  
   @yield('main')

   ...

   @yield('scripts')

</html>

Le nom de ces emplacements est clair et on peut ainsi préciser des règles CSS, placer le code principal et ajouter du JavaScript.

Ainsi dans la vue front/posts.blade.php, on utilise ces trois emplacements :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
@extends('front.layout')

@section('css')
    @if (Auth::check())
        <link rel="stylesheet" href="//cdn.jsdelivr.net/sweetalert2/6.3.8/sweetalert2.min.css">
    @endif
@endsection

@section('main')

   ...

@endsection

@section('scripts')

   ...

@endsection

On peut également déclarer une section dans le template avec @section lorsqu'il y a du code dedans qu'on veut soit utiliser, soit surcharger.

VI-B. L'inclusion

On peut faire beaucoup de choses avec l'héritage mais il est souvent utile de pouvoir inclure une vue dans une autre. Classiquement, on parle de vue partielle (partial).

VI-B-1. Les panneaux du tableau de bord

Il y a dans l'application un dossier partials pour le backend :

Image non disponible

On y trouve quatre vues partielles. La vue par défaut de l'administration (tableau de bord) est back/index.blade.php :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
@extends('back.layout')

@section('main')
    @admin
        <div class="row">
            @each('back.partials.pannel', $pannels, 'pannel')
        </div>
    @endadmin
@endsection

On a peu de code dans cette vue qui étend le layout et renseigne sa section main. La directive @each permet d'itérer dans un tableau ou une collection. Ici, on reçoit du contrôleur la variable $pannels qui contient les renseignements pour les panneaux d'information de l'administration :

Image non disponible

Pour chaque panneau, on utilise la vue back/partials/pannel en lui transmettant une variable $pannel :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
<div class="col-lg-3 col-xs-6">
    <!-- small box -->
    <div class="small-box bg-{{ $pannel->color }}">
        <div class="inner">
            <h3>{{ $pannel->nbr }}</h3>

            <p>{{ $pannel->name }}</p>
        </div>
        <div class="icon">
            <span class="fa fa-{{ $pannel->icon }}"></span>
        </div>
        <a href="{{ $pannel->url }}" class="small-box-footer">
            @lang('More info')
            <span class="fa fa-arrow-circle-right"></span>
        </a>
    </div>
</div>

On a ici la mise en forme du panneau et le renseignement des éléments grâce à la variable.

VI-B-2. Le menu latéral de l'administration

Le menu latéral de l'administration comporte des icônes, du texte et des sous-menus éventuels :

Image non disponible

Dans le layout (back/layout.blade.php), on trouve des appels à la vue partielle back.partials.treeview :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
@include('back.partials.treeview', [
  'icon' => 'user',
  'type' => 'user',
  'items' => [
    [
      'route' => route('users.index'),
      'command' => 'list',
      'color' => 'blue',
    ],
    [
      'route' => route('users.index', ['new' => 'on']),
      'command' => 'new',
      'color' => 'yellow',
    ],
  ],
])

On lui transmet un tableau de valeurs (icône, texte, route, couleur…). Ces informations sont exploitées dans la vue partielle pour créer l'élément de menu :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<li class="treeview">
    <a href="#"><i class="fa fa-fw fa-{{ $icon }}"></i> <span>@lang('admin.menu.' . $type . 's')</span>
        <span class="pull-right-container">
            <span class="fa fa-angle-left pull-right"></span>
        </span>
    </a>
    <ul class="treeview-menu">
        @foreach ($items as $item)
            <li><a href="{{ $item['route'] }}"><span class="fa fa-fw fa-circle-o text-{{ $item['color'] }}"></span> <span>@lang('admin.menu.' . $item['command'])</span></a></li>
        @endforeach
    </ul>
</li>

On dispose aussi des directives @includeIf et @includeWhen.

VI-C. Les composants

Comme alternative à l'inclusion, on dispose des composants qui sont apparus plus récemment. Voyons de quoi il s'agit.

Dans les dossiers des vues de l'application d'exemple, vous trouvez pour le backend un dossier components :

Image non disponible

Voyons le code de la vue alert :

 
Sélectionnez
1.
2.
3.
4.
<div class="alert alert-{{ $type }} alert-dismissible">
    <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
    <h4><span class="icon fa fa-check"></span>{{ $slot }}</h4>
</div>

On a le code HTML classique d'une barre d'alerte équipée d'un bouton de fermeture. Ce qui est intéressant se situe au niveau de la déclaration des classes et du texte :

 
Sélectionnez
class="alert alert-{{ $type }} alert-dismissible"
...
{{ $slot }}

On a deux variables :

  • $type : pour le type d'alerte (danger, succès…) ;
  • $slot : pour le texte de l'alerte.

Voyons comment on utilise ce composant…

Si vous regardez dans la vue back/users/edit.blade.php, vous trouverez ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
@if (session('user-updated'))
    @component('back.components.alert')
        @slot('type')
            success
        @endslot
        {!! session('user-updated') !!}
    @endcomponent
@endif

On teste si la session contient une variable user-updated et, si c'est le cas, on affiche le composant (@component) back.components.alert en renseignant les deux variables :

  • $type : on utilise la directive @slot en précisant le nom de la variable et son contenu ;
  • $slot : on aura dans cette variable tout ce qui n'est pas contenu dans une directive @slot, donc dans notre cas le contenu de la variable user-updated en session.

Vous pouvez regarder le code des deux autres composants qui sont basés sur le même principe.

On peut ajouter, si besoin, une information à transmettre au composant avec cette syntaxe :

 
Sélectionnez
@component('alert', ['element' => 'info'])

Cette possibilité n'a pas été utilisée dans l'application.

VI-D. Les structures de contrôle

VI-D-1. @if

La directive @if permet d'introduire une condition. Par exemple, dans la vue front/contact.blade.php, on trouve ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
@if ($errors->has('name'))
  @component('front.components.error')
    {{ $errors->first('name') }}
  @endcomponent
@endif

Cette partie du code gère l'éventuel message d'erreur de validation :

Image non disponible

On voit qu'il est fait usage d'un composant pour l'affichage de l'erreur, à savoir (front/components/error.blade.php) :

 
Sélectionnez
<span class="red">
    <strong>{{ $slot }}</strong>
</span>

un composant tout simple avec juste le slot.

VI-D-2. @else

La directive @else permet de compléter la logique. Par exemple dans la vue front/pagination.blade.php :

 
Sélectionnez
1.
2.
3.
4.
5.
@if ($paginator->onFirstPage())
    <span class="page-numbers prev inactive">@lang('pagination.previous')</span>
@else
    <a href="{{ $paginator->previousPageUrl() }}" class="page-numbers prev" rel="prev">@lang('pagination.previous')</a>
@endif

on n’a pas le même affichage selon la page.

VI-D-3. @unless

La directive @unless est l'inverse de @if. Par exemple, dans la vue front/comments/comments-base.blase.php :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
@unless ($comment->isLeaf())
    @php
        $level++;
    @endphp
    <ul class="children">
        @include('front/comments/comments', ['comments' => $comment->getImmediateDescendants()])
    </ul>
@endunless

on aurait pu écrire :

 
Sélectionnez
@if (!$comment->isLeaf())

mais c'est moins élégant…

Remarquez au passage la directive @php qui permet d'insérer du code PHP dans la vue.

VI-D-4. @isset et @empty

La directive @isset est l'équivalent de la fonction PHP isset(). Dans la vue back/components/box.blade.php, on trouve ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
@isset($footer)
    <div class="box-footer">
        {{ $footer }}
    </div>
@endisset

Si on a un footer, on l'affiche.

Il existe aussi la directive @empty équivalente de la fonction PHP empy() qui n'est pas utilisée dans l'application.

VI-D-5. @auth et @guest

Il est fréquent d'avoir à tester si un utilisateur est connecté, et on peut écrire :

 
Sélectionnez
@if (Auth::check())

mais il est plus élégant d'utiliser @auth. De la même manière, on dispose de @guest.

Il existe aussi la directive @switch équivalente de la directive PHP switch.

VI-D-6. Condition personnalisée

On peut aussi se construire une condition personnalisée. Regardez ce code dans AppServiceProvider :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
public function boot()
{
    ...

    Blade::if('admin', function () {
        return auth()->user()->role === 'admin';
    });

    Blade::if('redac', function () {
        return auth()->user()->role === 'redac';
    });

    Blade::if('request', function ($url) {
        return request()->is($url);
    });
}

On crée trois directives :

  • admin : vérifie qu'un utilisateur est administrateur ;
  • redac : vérifie qu'un utilisateur est rédacteur ;
  • request : vérifie que la requête correspond à une certaine URL.

Du coup, dans la vue front/layout.blade.php, on peut écrire :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
@admin
  <li>
    <a href="{{ url('admin') }}">@lang('Administration')</a>
  </li>
@endadmin
@redac
  <li>
    <a href="{{ url('admin/posts') }}">@lang('Administration')</a>
  </li>
@endredac

et dans la même vue :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
@request('password/reset')
  <li class="current">
    <a href="{{ request()->url() }}">@lang('Password')</a>
  </li>
@endrequest
@request('password/reset/*')
  <li class="current">
    <a href="{{ request()->url() }}">@lang('Password')</a>
  </li>
@endrequest

VI-D-7. Les boucles

Pour les boucles, on dispose de @for, @foreach, @each, @forelse et @while. La logique est la même que celle des directives équivalentes de PHP. Voyons un exemple dans la vue back/layout.blade.php :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@foreach ($breadcrumbs as $item)
  <li @if ($loop->last && $item['url'] === '#') class="active" @endif>
    @if ($item['url'] !== '#')
      <a href="{{ $item['url'] }}">
    @endif
    @isset($item['icon'])
      <span class="fa fa-{{ $item['icon'] }}"></span>
    @endisset
    {{ $item['name'] }}
    @if ($item['url'] !== '#')
      </a>
    @endif
  </li>
@endforeach

C'est la partie du code qui gère le breadcrumb :

Image non disponible

Avec @foreach, on itère dans les éléments de la variable @breadcrumbs. Avec cette directive, on dispose de la variable interne $loop qui offre des informations sur l'index en cours. Voici tout ce qui est disponible :

Propriété

Description

$loop->index

L'index en cours (commence à 0)

$loop->iteration

L'itération courante (commence à 1)

$loop->remaining

Les itérations restantes

$loop->count

Le nombre total d'itérations

$loop->first

Indique si c'est le premier élément

$loop->last

Indique si c'est le dernier élément

$loop->depth

Le niveau d'imbrication actuel

$loop->parent

La variable d'itération parente si imbrication

Dans notre code on vérifie si on a le dernier élément avec $loop->last. On utilise alors quelques directives qu'on a déjà vues.

VI-E. L'injection de service

Normalement, on envoie à une vue toutes les informations nécessaires à partir du contrôleur, mais parfois on a besoin d'un service spécifique : on peut alors utiliser la directive @inject. Vous pouvez trouver un exemple dans la vue back/settings.blade.php :

 
Sélectionnez
@inject('envRepository', 'App\Repositories\EnvRepository')

Le service est fourni par la classe App\Repositories\EnvRepository (c'est un repository pour interagir avec le fichier .env) dont une instance va se trouver dans la variable $envRepository. On peut ainsi écrire ensuite dans la vue ce code :

 
Sélectionnez
$envRepository->get('APP_URL')

Ici, on peut récupérer la valeur pour l'élément APP_URL du fichier .env. Elle est ainsi affichée dans les réglages :

Image non disponible

VI-F. Les composeurs de vue (view composers)

Les « composeurs de vue » sont des fonctions de rappel ou des classes qui sont appelées lorsqu'une vue est générée, ce qui permet de localiser du code. Voyons un exemple dans l'application.

Regardez ce code dans AppServiceProvider (on aurait pu créer un provider spécifique) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public function boot()
{
    ...

    view()->composer('front.layout',MenuComposer::class);

    view()->composer('back.layout',HeaderComposer::class);

    ...
}

Avec la première ligne, on dit que lorsque la vue front/layout.blade.php est générée, on doit appeler la classe App\Http\ViewComposers\MenuComposer.

Les classes pour les composeurs de vue sont toutes rangées dans ce dossier :

Image non disponible

Voyons cette classe :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;
use App\Models\Category;

class MenuComposer
{
    /**
     * Bind data to the view.
     *
     * @param  View  $view
     * @return void
     */
    public function compose(View $view)
    {
        $view->with('categories', Category::select('title', 'slug')->get());
    }
}

On constate qu'on envoie (with) dans la vue une variable $categories avec les titres des catégories. C'est pour renseigner ce sous-menu :

Image non disponible

On a constaté que la vue front/layout.blade.php est le template de base pour toutes les vues du frontend. Si on ne passait pas par l'intermédiaire d'un composeur de vue, il faudrait envoyer les catégories dans toutes les vues ! Ici on a le code en un seul endroit.

C'est la même logique pour la classe HeaderComposer en ce qui concerne le template du backend : elle est juste un peu plus chargée parce qu'on doit gérer le breadcrumb, les titres et les notifications.

VI-G. En résumé

Avec Blade on peut :

  • utiliser l'héritage de vue ;
  • inclure une vue ;
  • utiliser un composant ;
  • utiliser de nombreuses directives pour organiser le code ;
  • utiliser des boucles ;
  • injecter un service.

D'autre part, les composeurs de vue permettent de localiser du code facilement.


précédentsommairesuivant

Copyright © 2018 Maurice Chavelli. 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.