W31 - Programmation Web
côté serveur

{{ 3 - Laravel }}

Adrien Krähenbühl IUT Robert Schuman

Avant de commencer

Version de Laravel
Ce cours se base entièrement sur Laravel 8, version sortie le 8 septembre 2020.

Rappel doc & stackoverflow-like
  • Ne recopiez pas bêtement
  • La seule aide fiable est la doc officielle sur php.net… et Laravel.com.
QCM n°3
  • Noté
  • Sur Moodle
  • Au début du prochain TD
  • Pourra faire appel aux concepts des CM 1 et 2

Ce que l’on a vu

Partie 1

  1. Syntaxe PHP
  2. Concept client-serveur
  3. Envoi de données en GET et POST
  4. Persistance des données avec les cookies et les sessions

Partie 2

  1. Fonctions
  2. PHP Objet ($this, __construct)
  3. Mécanisme d’exceptions : try / catch / throw
  4. SQLite & PDO : requêtes préparées
  5. Design MVC pour une application web

Au programme aujourd’hui


  1. Présentation du framework
  2. Le routage
  3. Les contrôleurs
  4. Les vues avec le moteur de rendu Blade
  5. (Les middlewares)


La suite (et la fin) du module

1 TD + 2 TPs
  • Routage, vues et contrôleurs
1 TD + 5 TPs
  • Blade et Eloquent
  • Mise en pratique sur un mini-projet
1 TP noté (en Décembre ou Janvier)
  • Compétences évaluées :
    1. PHP : maîtrise de la syntaxe du langage
    2. POO : conception qui respecte les concepts de POO
    3. MVC : organisation du code selon l’architecture MVC
    4. Laravel : utilisation pertinente du framework
  • Objectif : réussir à décontextualiser les compétences acquises.

Le framework Laravel

Laravel, c’est quoi ?



Laravel, c’est framework PHP, c’est-à-dire un environnement qui facilite la création de sites et services web.

Il en existe d’autres : Symfony, CodIgniter, Phalcon, Yii, etc.

Pourquoi choisir Laravel ?


Recherches Google des principaux framework PHP dans le monde.

  • Laravel est le framework PHP le plus utilisé
  • Laravel est open-source, sous license MIT
  • Laravel utilise astucieusement plusieurs bibliothèques PHP qui ont fait leurs preuves : symfony, monolog, eloquent, etc.

Laravel est MVC

MVC, encore et toujours


MVC (Modèle-Vue-Contrôleur) est une architecture logicielle qui propose un découpage en trois entités :

  • le Modèle qui représente les données,
  • la Vue qui définie l’affichage du modèle,
  • le Contrôleur qui contient la logique de l’application et répond aux requêtes utilisateur en coordonnant les modèles et les vues.

Le MVC avec Laravel


Routage
Toutes les requêtes utilisateur sont interceptées par le contrôleur d’entrée routes/web.php qui la dirige vers le bon contrôleur (ou sélectionne la vue désirée).
Modèle
  • La classe User représente un utilisateur de la BDD
  • La connexion à la BDD est maintenant gérée par Laravel
Contrôleur
  • La classe UserController traite les requêtes concernant les utilisateurs.
  • Elle est appelée à bon escient par le contrôleur d’entrée web.php.
  • Elle manipule des objets de type User
Vue
  • Les vues contiennent le code HTML des réponses aux requêtes.
  • Elle peuvent contenir du code PHP pour personnaliser l’affichage de chaque client (notamment à travers les sessions).

Le routage

Qu’est-ce que c’est ?


Le routage est :
  • un mécanisme de contrôle exécuté à la réception d’une requête.
  • l’unique interface entre la requête et le reste de l’application.

Les routes simples

Route::get ( 'index', function() { return "GET";  } );
Route::post( 'index', function() { return "POST"; } );
Route::any ( 'index', function() { return "ANY";  } );

Extrait du fichier routes/web.php du site http://site.fr/


Spécifier une route, c’est indiquer la fonction à exécuter lorsqu’on reçoit une requête pour une URL donnée avec un protocole HTTP donné.

  • Le routage est spécifié dans le fichier routes/web.php
  • Le routage est effectué via la facade singleton Route (A31 💙)
  • Les routes non spécifiées produiront une réponse 404.

Les routes paramétrées

Route::get (
    'index/{var1}/{var2}',
    function( string $var1, int $var2 ) : string {
        return "GET avec ".$var1." et ".$var2;
    }
);

routes/web.php

http://site.fr/index/W/31

GET avec W et 31

http://site.fr/index/Z/666

GET avec Z et 666


Routage des URL de la forme http://site.fr/index/[text]/[integer]


  • Une route peut déclarer des paramètres avec des accolades.
  • Chaque paramètre déclaré devient un argument de la fonction à exécuter.

Les groupes de routes préfixés

Route::prefix('admin')->group( function () {

    Route::get('/',     function() { return "GET admin"; });
    Route::get('index', function() { return "GET admin/index"; });
    Route::get('stats', function() { return "GET admin/stats"; });

});

routes/web.php

http://site.fr/admin

GET admin

http://site.fr/admin/index

GET admin/index

http://site.fr/admin/stats

GET admin/stats


Les groupes préfixés
  • permettent d’organiser les routes.
  • définissent un début d’URL commun à toutes les routes du groupe.

Routage et vues

Afficher une vue

Exemple d’une requête vers http://site.fr/accueil

Route::get( 'accueil', function () {
    return view('index');
});

routes/web.php

<!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>Page d'accueil</title>
    </head>
    <body>Bonjour !</body>
</html>

resources/views/index.php


  • Pour ne pas écrire le code HTML au niveau des routes, Laravel propose un mécanisme de vues
  • Les vues doivent être placées dans resources/views/
  • Le paramètre de la directive view() doit être le nom du fichier sans extension

Transmettre des données à une vue

// Possibilité n°1
Route::get( 'accueil', function () {
    return view('index', ['name'=>'W31']);
});
// Possibilité n°2
Route::view(
    'accueil', 'index', ['name'=>'W31']
);

routes/web.php

<!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>Page d'accueil</title>
    </head>
    <body>
        Bonjour <?= $name ?> !
    </body>
</html>

resources/views/index.php


  • Les données sont transmises dans un tableau dont chaque entrée est convertie en variable dans la vue.
  • La méthode Route::view() correspond au protocole GET et s’utilise pour afficher une vue sans contrôle.

Les Contrôleurs

Qu’est-ce que c’est ?


  • Un contrôleur contient la logique applicative pour répondre aux requêtes.
  • Un contrôleur manipule les modèles et les vues avec pour objectif de construire le résultat.
  • Dans Laravel, c’est au niveau du routage qu’est décidé quelle méthode de quel contrôleur appeler.

Les classes de contrôleurs

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MyController extends Controller
{
  public function __construct() { ... }
  public function myMethod( Request $request ) { ... }
}

app/Http/Controllers/MyController.php

Un contrôleur
  • est une classe qui étend la classe Controller de Laravel
  • doit être placé dans le répertoire app/Http/Controllers


namespace : espace de noms virtuel du contrôleur (\(\approx\) package de Java)
use : import d’une classe ou d’un namespace (\(\approx\) import de Java)

Routage vers un contrôleur

Route::get( 'accueil', [MyController::class,'index'] );

routes/web.php

\(\rightarrow\)

Bonjour W31 !

http://site.fr/accueil

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MyController extends Controller
{
    public function index(Request $request) {
        return view('index', ['name'=>'W31']);
    }
}

app/Http/Controllers/MyController.php

\(\rightarrow\)

<!doctype html>
<html lang="fr">
    <head>
        <meta charset="utf-8">
        <title>Page d'accueil</title>
    </head>
    <body>
        Bonjour <?= $name ?> !
    </body>
</html>

resources/views/index.php

Une méthode publique d’un contrôleur peut être utilisée comme fonction à exécuter pour une route avec cette syntaxe :

[NomDeLaClasse::class,'nomDeLaMéthode']

Un bon contrôleur

Un contrôleur Laravel bien construit doit :

  • répondre aux normes de la POO,
  • contenir la logique de traitement de requêtes,
  • avoir ses données associées à un ou plusieurs modèles,
  • ne contenir aucune instruction d’accès direct à une BDD.

Une règle essentielle :

Low coupling, High cohesion

Blade, le moteur de vues

Qu’est-ce qu’un moteur de vues ?

Moteur de vues
(Template Engine en anglais.) Mécanisme permettant d’écrire des vues de façon plus souple en intégrant par exemple de l’héritage ou des structures de contrôle.
  • C’est un meta-langage qui génère du code pour un langage cible.
  • Il existe une multitude de moteurs de vues comme par exemple Smarty, Twig, Mustache, etc.

Blade, le moteur de vues de Laravel


Laravel utilise son propre moteur de vues : Blade.

Avantage
Les vues Blade sont compilées en PHP. Il n’y a donc pas de processus supplémentaire lié à Blade. Lorsqu’on accède à une vue, elle aura déjà été transformée en code PHP.

Note : Les vues Blade doivent avoir pour extension .blade.php.

Définir un layout

Un layout est une page modèle qui peut être étendue.

<html>
    <head><title>@yield('title')</title></head>
    <body>
        @yield('header')
        @section('content')
            <nav>...</nav>
        @show
    </body>
</html>

resources/views/myLayout.blade.php

@extends('myLayout')

@section('title', 'Mon titre')
@section('header') <h1>Ma page</h1> @endsection

@section('content')
    @parent
    <p>Le contenu central de ma page.</p>
@endsection

resources/views/child.blade.php

<html>
    <head>
        <title>Mon titre</title>
    </head>
    <body>
        <h1>Ma page</h1>
        <nav>...</nav>
        <p>Le contenu central de ma page.</p>
    </body>
</html>

Résultat.

@yield('name')
déclare une section name qui sera définie dans une page enfant.
@section('name')
  • (layout) définit une section qui peut être surchargée.
  • (enfant) définit une section qui a été déclarée dans le layout.

Transmettre des données

Route::get('myName', function () {
  return view('vue', ['name'=>'Bond']);
});

routes/web.php

Mon nom est {{ $name }},
James {{ $name }}.

vue.blade.php

Mon nom est Bond, James Bond.

http://.../myName


Les données :

  • sont transmises à la vue via un tableau en argument de view()
  • sont accessibles dans la vue dans des doubles accolades {{ }}.
  • sont protégées des attaques XSS.

Attention : tout se passe côté serveur, entre le contrôleur et la vue.
Il ne s’agit pas transmission de données depuis/vers le client.

Condition If

@if ($name === "Bond")
    Mon nom est {{ $name }},
    James {{ $name }}
@elseif ($name === "Pile")
    Mon nom est {{ $name }},
    Jean {{ $name }}.
@else
    Mon nom est {{ $name }}.
@endif

vue.blade.php

return view('vue', ['name'=>'Bond']);

Mon nom est Bond, James Bond.

return view('vue', ['name'=>'Pile']);

Mon nom est Pile, Jean Pile.

return view('vue', ['name'=>'Personne']);

Mon nom est Personne.

Les conditions peuvent concerner n’importe quelle variable PHP accessible depuis la vue :

  • des variables transmises par le contrôleur
  • des variables de session

Conditions isset, empty et switch

Instructions duales isset et empty

@isset( $name )
    Mon nom est {{ $name }}.
@endisset
@empty( $name )
    Mon nom est Tu-Sais-Qui.
@endempty

vue.blade.php

view('vue',['name'=>'Bond']);

Mon nom est Bond.

view('vue');

Mon nom est Tu-Sais-Qui.


L’instruction switch

@switch( $name )
  @case('Bond')
    Mon nom est {{ $name }},
    James {{ $name }}.
  @default
    Mon nom est Tu-Sais-Qui.
@endswitch

vue.blade.php

view('vue', ['name'=>'Bond']);

Mon nom est Bond, James Bond.

view('vue');

Mon nom est Tu-Sais-Qui.

Boucles for et foreach

La boucle for

@for( int $i=1 ; $i<=$buts ; $i++ )
Et {{ $i }}
@endfor
Zéro.

1998.blade.php

return view('1998',['buts' => 3]);

Et 1, Et 2, Et 3 Zéro.


La boucle foreach

@foreach( $buts as $i )
Et {{ $i }},
@endforeach
Zéro.

1998v2.blade.php

view('1998v2', ['buts' => ['un','deux','trois']]);

Et un, Et deux, Et trois Zéro.

Les Middleware

Qu’est-ce que c’est ?


  • Dans le contexte de Laravel, un middleware est un contrôleur spécifique dont le but est de filtrer des requêtes
  • Exemples : authentification, journalisation, vérification des données, etc.
  • Laravel permet de mettre en place facilement des middlewares pour une route, un groupe de routes ou un contrôleur.

Les classes de Middleware

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class MyMiddleware {
    public function handle( Request $request, Closure $next ) {
        // Code à exécuter AVANT le traitement de la requête $request
        $res = $next($request);
        // Code à exécuter APRÈS le traitement de la requête $request
        return $res;
    }
}
Un middleware
  • est une classe sans aucun héritage avec une méthode handle(Request $request, Closure $next)
  • décore l’exécution “normale” de requêtes
  • mutualise du code de contrôle récurrent
  • se place dans le répertoire app/Http/Middleware

Middleware global

class Kernel extends HttpKernel {
    ...
    protected $middleware = [
        ...
        \App\Http\Middleware\MyMiddleware::class
    ];
    ...
}

app/Http/Kernel.php

  • Pour faire exécuter un middleware pour toutes les requêtes HTTP, on le déclare dans le tableau $middleware, attribut de la classe Kernel.
  • Le nom à indiquer doit être de la forme suivante :

\Namespace\De\La\Classe\NomDeLaClasse::class

Middleware sur une route

class Kernel extends HttpKernel {
    ...
    protected $routeMiddleware = [
        ...
        "myMiddleware" => \App\Http\Middleware\MyMiddleware::class
    ];
    ...
}

app/Http/Kernel.php

Route::get( 'accueil', ... )->middleware('myMiddleware');

routes/web.php

Un middleware
  • se déclare dans le tableau $routeMiddleware de Kernel.php,
  • s’utilise dans routes/web.php avec la méthode ->middleware().

Les groupes de middleware

class Kernel extends HttpKernel {
    ...
    protected $middlewareGroups = [
        "myMidGroup" => [ \App\Http\Middleware\MyMiddleware::class,
                      \App\Http\Middleware\MyOtherMiddleware::class ]
    ];
    ...
}

app/Http/Kernel.php

Route::get( 'accueil', ... )->middleware('myMidGroup');
Route::middleware(['myMidGroup'])->group( ... );

routes/web.php

Un groupe de middleware
  • se déclare dans le tableau $middlewareGroups de Kernel.php,
  • s’utilise dans routes/web.php,
  • permet d’associer plusieurs middlewares à une route ou un groupe de routes.

Combo : middleware sur route préfixée

Route::prefix('admin')->middleware('myMidGroup')->group(
    function () {
        Route::get ('accueil', ... );
        Route::post( ... );
    }
);

routes/web.php


Associer un middleware à un groupe préfixé permet d’organiser ses routes par préfixe avec une sémantique claire.

C’est à vous, développeurs, d’utiliser à bon escient les préfixes et middlewares pour organiser et mutualiser votre code.