12. Conclusion
Ce document a présenté la construction d'une application web MVC avec le framework [Laravel] : une application dont les pages HTML sont fabriquées par le serveur, avec des vues [Blade], sans framework [JavaScript] côté navigateur. Il a suivi pas à pas la progression du cours [Flask], lui-même issu des cours [Spring MVC], [ASP.NET Core MVC] et [NestJS] : des actions et du routage vers les vues, les formulaires, l'internationalisation, la sécurité et l'accès aux données, puis une étude de cas complète.
Les mêmes 28 exemples et la même application ont ainsi été écrits avec cinq frameworks, en [TypeScript], en [C#], en [Java], en [Python] et en [PHP]. Les notions sont les mêmes ; seuls les noms et les mécanismes changent. Les correspondances entre [Flask] et [Laravel] :
[Flask] | [Laravel] |
fabrique [create_app], objets rangés dans [app.extensions] | [bootstrap/app.php], fournisseurs de services, conteneur ([$singletons], injection par le constructeur) |
[requirements.txt], environnement virtuel, [pip] | [composer.json], [composer.lock], dossier [vendor], [Composer] |
[config.py], variables [FLASK_...] ([app.config]) | fichier [.env], dossier [config], fonctions [env] et [config] |
blueprints, [@bp.get], [@bp.post] | [routes/web.php], contrôleurs, routes nommées, groupes de routes |
[render_template], [redirect], [url_for] | [view], [redirect], [route] |
[request.args], [request.form], convertisseurs ([<int:id>]) | objet [Request], paramètres d'action, contraintes ([whereNumber]), liaison de modèle |
[Pydantic] ; [WTForms] : validateurs, [form.validate()], [form.errors] | [Validator], requêtes de formulaire ([FormRequest]), règles, [$errors], [old()] |
vues [Jinja2], [{{ }}], [{% for %}], [{% if %}] | vues [Blade], [{{ }}], [@foreach], [@if] |
[{% extends %}] et blocs, [{% include %}], macros | [@extends] et sections, [@include], composants ([<x-...>]) |
processeur de contexte ([@app.context_processor]) | compositeur de vue ([View::composer]) |
messages flash ([flash]), dans le cookie de session signé | données flash de la session ([session()->flash], [with]), session en fichiers ou en cookie chiffré |
[before_request], [after_request], [teardown_request] | middlewares (globaux, de groupe, de route), méthode [terminate] |
[@app.errorhandler] | [withExceptions], [render], [abort] |
[before_request] et décorateurs écrits à la main ([PyJWT], [bcrypt]) | gardes ([Auth::viaRequest]), middleware [auth], [Gate], façade [Hash] ([firebase/php-jwt]) |
[CSRFProtect] de [Flask-WTF] | middleware [PreventRequestForgery], directive [@csrf] (réponse 419) |
dictionnaires JSON, fonction [t(...)] écrite à la main | dossier [lang], fonction [__()], [App::setLocale] |
[Babel] | [Carbon] ([isoFormat]), [Number] (extension [intl]) |
dictionnaires en mémoire, [threading.Lock] | cache ([Cache], [Cache::lock]), [RateLimiter] |
[SQLAlchemy] : entités déclaratives, [select(...)], sessions | [Eloquent] : modèles, constructeur de requêtes, relations ([belongsTo], [with]) |
[with sessions.begin() as session:] | [DB::transaction(...)] |
[version_id_col], géré par [SQLAlchemy] | [WHERE version = ?] et [version + 1], écrits dans la couche DAO |
[python app.py] en mode debug (rechargement automatique) | [php artisan serve] (rien à recharger : chaque requête relit le code) |
serveur WSGI : [Waitress], [Gunicorn] | serveur web ([nginx], [Apache]) et [PHP-FPM] |
Par rapport à [Flask], on retiendra surtout :
- [Laravel] est un framework complet (*full-stack*) : routage, vues, validation, session, cache, authentification, traduction, accès aux données, envoi de courriels, files de tâches... tout est fourni, et tout est conçu pour fonctionner ensemble. C'est l'opposé du micro-framework [Flask] : beaucoup moins de code à écrire, mais un framework plus vaste à connaître, où bien des choses se passent « d'elles-mêmes » (la session, les cookies chiffrés, le jeton anti-CSRF, le retour au formulaire après une erreur de saisie). Le chapitre sur le cycle de vie d'une requête, et l'examen des requêtes avec [curl], ont servi à rendre visible ce qui se passe ;
- l'application [PHP] est reconstruite à chaque requête (exemple 01) : rien ne survit en mémoire d'une requête à la suivante. Ce qui doit durer va dans la session (un utilisateur), le cache (tous les utilisateurs), la base de données ou les cookies. En contrepartie, une modification du code est prise en compte sans redémarrage, et une requête qui échoue n'affecte jamais les suivantes ;
- le conteneur de services fabrique les contrôleurs, les middlewares et les services, et leur fournit leurs dépendances d'après les types de leur constructeur : l'injection de dépendances est au cœur du framework, comme dans [Spring] ou [ASP.NET Core] ;
- les façades ([Cache::], [DB::], [Auth::], [Hash::]...) et les fonctions globales ([view], [redirect], [session], [config], [__]...) donnent accès aux services partout, en une ligne. C'est très pratique ; c'est aussi un moyen de cacher les dépendances d'une classe, que l'injection par le constructeur rend, elle, visibles ;
- presque tout est middleware : les cookies, la session, la protection anti-CSRF, l'authentification, les autorisations, et nos propres contrôles (la langue, les rôles, le laissez-passer). Un même mécanisme sert à toutes les requêtes, à un groupe de routes, ou à une seule ;
- [PHP] est un langage dont le typage est vérifié à l'exécution : les types déclarés des paramètres, des propriétés et des résultats ([int], [?Client], [Collection]) sont contrôlés à chaque appel. Les classes [readonly], les énumérations, la promotion de constructeur, les arguments nommés, l'opérateur nullsafe ([?->]) en ont fait, depuis la version 8, un langage expressif et sûr ;
- [Eloquent] suit le modèle Active Record : un modèle sait se lire et s'écrire lui-même ([Medecin::find(1)], [$medecin->save()]), avec très peu de code. Ses requêtes restent proches du SQL qu'elles produisent, et l'écoute des requêtes ([DB::listen]) permet de vérifier ce qui est envoyé à la base. Il faut penser au chargement anticipé des relations ([with]), sans quoi l'on retombe vite dans le problème des « N + 1 requêtes » ;
- les vues [Blade] sont compilées en [PHP], et mises en cache : elles sont rapides, échappent automatiquement ce qu'elles affichent, et leurs composants ([<x-champ>]) rendent les formulaires concis.
L'étude de cas montre qu'une application HTML classique, sans [JavaScript] indispensable, reste une solution simple et robuste : chaque page est une URL, le bouton « précédent » du navigateur fonctionne, et le serveur contrôle tout. Le peu de [JavaScript] utilisé (les fenêtres de confirmation) améliore le confort sans être nécessaire au fonctionnement. [Laravel] sait aussi servir des applications plus interactives, sans quitter [PHP] ([Livewire]) ou avec un framework [JavaScript] côté navigateur ([Inertia], avec [Vue.js] ou [React]) : ce sera l'objet d'autres documents.
Pour aller plus loin, on pourra consulter la documentation de [Laravel] (laravel.com/docs), en particulier les pages consacrées au cycle de vie d'une requête, au conteneur de services, à la validation, à [Blade] et à [Eloquent], celle de [PHP] (php.net/manual/fr), celle de [Composer] (getcomposer.org/doc), et comparer cette application à ses sœurs [Flask], [Spring MVC], [ASP.NET Core MVC] et [NestJS].