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 :
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 :
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 :
Ce template comporte la structure globale des pages et est déclaré comme parent par les autres vues :
@extends
('front.layout'
)
Dans le template on prévoit trois emplacements (@yield) pour que les vues enfants puissent placer leur code :
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 :
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 :
On y trouve quatre vues partielles. La vue par défaut de l'administration (tableau de bord) est back/index.blade.php :
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 :
Pour chaque panneau, on utilise la vue back/partials/pannel en lui transmettant une variable $pannel
:
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 :
Dans le layout (back/layout.blade.php), on trouve des appels à la vue partielle back.partials.treeview :
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 :
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 :
Voyons le code de la vue alert :
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 :
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 :
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 : |
@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 :
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 :
On voit qu'il est fait usage d'un composant pour l'affichage de l'erreur, à savoir (front/components/error.blade.php) :
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 :
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 :
on aurait pu écrire :
@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 :
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 :
@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 :
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 :
et dans la même vue :
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 :
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 :
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 |
---|---|
|
L'index en cours (commence à 0) |
|
L'itération courante (commence à 1) |
|
Les itérations restantes |
|
Le nombre total d'itérations |
|
Indique si c'est le premier élément |
|
Indique si c'est le dernier élément |
|
Le niveau d'imbrication actuel |
|
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 :
@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 :
$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 :
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) :
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 :
Voyons cette classe :
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 :
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.