tite fractale

Introduction à MVC via PHP

1. Introduction

MVC est un paradigme de conception de systèmes interactifs. C’est une façon de les structurer en séparant trois concepts :

Une telle séparation permet de :

1.1. Remarques

1.2. Objet de l’activité

Au cours de cette activité, nous allons construire une application web de type CRUD, pour :

Voir l’article Wikipedia correspondant.

1.3. Tant pis

1.3.1. Outils dépassés

Nous utiliserons le langage PHP (tant pis) et organiserons notre code selon un autre paradigme important, la Programmation Orientée Objet (tant pis).

Les données seront stockées dans une base MySQL (tant pis).

1.3.2. Réinvention de la roue

Certains cadriciels PHP pour applications web sont conçus autour de MVC (voir une liste plus bas), mais ici, pour des raisons pédagogiques, nous n’utiliseront pas de framework moderne (tant pis). En revance, nous utiliserons un framework pédagogique : my.very.cute (voir plus bas).

Travailler avec un cadriciel PHP n’est pas destiné aux débutants. Cependant, une fois compris le statut de générateur de HTML, et avec quelques notions de programmation objet, l’utilisation d’un cadriciel est souhaitable :

1.4. Tant mieux

1.4.1. Installation

Pour installer Apache, MySQL et PHP sur Windows, il existe de nombreux projets qui englobent le tout. UWAMP est un de ceux-là. Sinon :

1.4.2. Développement dirigé par les tests

Nous appliquerons autant que possible la méthode TDD, pour Tests Driven Development. Voir l’article Wikipedia.

Pour cela nous utiliserons urlrulz, un petit programme en Python3 qui teste des sites automatiquement.

Tant qu’on est dans les bonnes pratiques, un suivi des versions de votre travail peut être intéressant.

git bien sûr !

2. Contrôleur

2.1. Définition

Dans une application web, il gère généralement les traitements (parfois appelés la logique) à effectuer suivant différentes informations comme :

Certains traitements consisteront en une lecture ou une écriture dans la couche de persistance, au travers donc du M. Pour afficher les résultats, il les transmettra à V qui se chargera de la présentation.

2.2. Pour simplifier

Schéma MVC sans M ni V

crédits schéma

La distinction répartiteur-contrôleur est une coquetterie. C’est juste bien dans un framework d’avoir un fichier fixe (même s’il contient en peu de config, qui mériterait d’être externalisée), et un fichier dans lequel on code.

2.3. Activité Contrôleur

2.3.1. Mise en place

2.3.2. URL mapping

Voici un exemple de plan classique d’un site de type CRUD :

URL Description C, R, U ou D
http://127.0.0.1/mvc/index.php/méthode/arg1/arg2 cas général
http://127.0.0.1/mvc/ accueil
http://127.0.0.1/mvc/index.php accueil
http://127.0.0.1/mvc/index.php/ accueil
http://127.0.0.1/mvc/index.php/persos liste des personnages (html) R
http://127.0.0.1/mvc/index.php/persos/html liste des personnages (html) R
http://127.0.0.1/mvc/index.php/persos/csv liste des personnages (csv) R
http://127.0.0.1/mvc/index.php/perso/3 afficher le perso n°3 (html) R
http://127.0.0.1/mvc/index.php/perso/3/html afficher le perso n°3 (html) R
http://127.0.0.1/mvc/index.php/perso/3/csv afficher le perso n°3 (csv) R
http://127.0.0.1/mvc/index.php/nouveau créer un personnage, formulaire C
http://127.0.0.1/mvc/index.php/nouveau + POST créer un personnage, confirmation C
http://127.0.0.1/mvc/index.php/edit/3 modifier le perso n°3, formulaire U
http://127.0.0.1/mvc/index.php/edit/3 + POST modifier le perso n°3, confirmation U
http://127.0.0.1/mvc/index.php/delete/3 supprimer le perso n°3, formulaire D

2.3.3. Remarques

2.3.4. Codage du contrôleur

2.3.4.1. Existence seulement

Télécharger (ou cloner) urlrulz et vérifier qu’il fonctionne bien.

Dans controller.php, écrire les méthodes correspondant au plan du site défini dans le tableau ci-dessus. Le site devra passer les tests urlrulz ci-dessous (téléchargeables ici) :

http://127.0.0.1/mvc/
http://127.0.0.1/mvc/index.php
http://127.0.0.1/mvc/index.php/
http://127.0.0.1/mvc/index.php/persos
http://127.0.0.1/mvc/index.php/persos/html
http://127.0.0.1/mvc/index.php/persos/csv
http://127.0.0.1/mvc/index.php/perso/3
http://127.0.0.1/mvc/index.php/perso/3/html
http://127.0.0.1/mvc/index.php/perso/3/csv
http://127.0.0.1/mvc/index.php/perso/5
http://127.0.0.1/mvc/index.php/perso/5/html
http://127.0.0.1/mvc/index.php/perso/5/csv
http://127.0.0.1/mvc/index.php/nouveau
http://127.0.0.1/mvc/index.php/edit/3
http://127.0.0.1/mvc/index.php/delete/3

La simple existence de méthodes bien choisies permettra d’éviter des 404 pour ces URLs.

Attention : Il se peut que votre serveur local ne soit pas configuré correctement pour cette activité. Après avoir fait exprès de faire une erreur de syntaxe PHP dans le contrôleur, vérifier qu’une erreur de type 500 est renvoyée au client.

2.3.4.2. Un peu de contenu

Désactiver le mode débogage et, à l’aide d’instructions echo bien senties, débrouillez-vous pour que le site passe les tests urlrulz ci-dessous (téléchargeables ici) :

http://127.0.0.1/mvc/                       accueil
http://127.0.0.1/mvc/index.php              accueil
http://127.0.0.1/mvc/index.php/             accueil
http://127.0.0.1/mvc/index.php/persos       liste html
http://127.0.0.1/mvc/index.php/persos/html  liste html
http://127.0.0.1/mvc/index.php/persos/csv   liste csv
http://127.0.0.1/mvc/index.php/perso/3      perso 3 html
http://127.0.0.1/mvc/index.php/perso/3/html perso 3 html
http://127.0.0.1/mvc/index.php/perso/3/csv  perso 3 csv
http://127.0.0.1/mvc/index.php/perso/5      perso 5 html
http://127.0.0.1/mvc/index.php/perso/5/html perso 5 html
http://127.0.0.1/mvc/index.php/perso/5/csv  perso 5 csv
http://127.0.0.1/mvc/index.php/nouveau      nouveau
http://127.0.0.1/mvc/index.php/edit/3       modif perso 3
http://127.0.0.1/mvc/index.php/delete/3     suppression perso 3

Il faut que la réponse du site (ce que la méthode echora) soit exactement ce qui est proposé ci-dessus. Penser à utiliser les paramètres optionnels.

Une erreur de correspondance surprenante pourrait arriver :

...
Testing http://127.0.0.1/mvc/index.php/persos        liste html...
At http://127.0.0.1/mvc/index.php/persos     liste html, expected
'html' but got
<!-- du HTML, du HTML, et encore du HTML en pagaille, à savoir reconnaître -->

3. Modèle

3.1. Définition

Le MODÈLE modélise la couche métier et s’occupe de la persistance. En d’autres termes, il réalise une abstraction sous deux angles :

3.2. Pour simplifier

Pour l’instant, nous n’incorporons pas le V.

Schéma MVC sans V

crédits

3.3. Activité Modèle

3.3.1. Données

Créer une base de données MySQL nommée personnages, puis initialisez-là avec ce script.

3.3.2. Codage du modèle

Voir TP précédent, dont une correction est fournie plus loin.

Une classe s’occupe de modéliser un personnage, une autre s’occupe de gérer ces personnages.

3.3.3. Tests

Il est possible d’utiliser des tests unitaires contre le modèle. Voir ce squelette.

3.4. Activité Modèle-Contrôleur

3.4.1. Mise en place

 

// Include model files.
foreach (glob("m_*.php") as $filename) include $filename;

public function la_suite() {
    $mng = new PersonnagesManager();
    foreach ($mng->getList() as $perso) {
        echo  $perso->getNom();
    }
}

À quelle URL peut-on tester ces dernières lignes de PHP ?

3.4.2. Lectures sans vrai HTML

Objectif : ces tests urlrulz (téléchargeables ici) doivent passer.

http://127.0.0.1/mvc/                        accueil
http://127.0.0.1/mvc/index.php               accueil
http://127.0.0.1/mvc/index.php/              accueil
http://127.0.0.1/mvc/index.php/perso/3       <b>Fou</b>
http://127.0.0.1/mvc/index.php/perso/3/html  <b>Fou</b>
http://127.0.0.1/mvc/index.php/perso/3/csv   Fou
http://127.0.0.1/mvc/index.php/persos        Roi Reine Fou Tour Combattant Soldat Garde Fantassin Alerte Déesse Amazone
http://127.0.0.1/mvc/index.php/persos/html   Roi Reine Fou Tour Combattant Soldat Garde Fantassin Alerte Déesse Amazone
http://127.0.0.1/mvc/index.php/persos/csv    Roi,Reine,Fou,Tour,Combattant,Soldat,Garde,Fantassin,Alerte,Déesse,Amazone

3.4.3. Lectures avec HTML

Compléter le projet pour en faire un site navigable, toujours à l’aide de l’instruction echo, et toujours sans aucun formulaire : que des lectures.

Attention : Dans un premier temps, on ne cherche pas à produire du HTML de compétition. Ne tapez que le strict minimum au niveau des balises (pas de <html>, <head>, <title>…, mais des <h1>, <a>, <ul>…) et ne cherchez pas à faire beau.
Juste navigable, avec par exemple :

3.4.4. Écritures

Note : Cette partie est fastidieuse, vous pourrez y revenir une fois que le concept de vue aura été compris.

Compléter le projet pour que l’on puisse opérer des créations, modifications et des suppressions. Vous aurez besoin de gérer des formulaires, à l’ancienne.

3.5. Problèmes

C’est ce que le V va tenter de résoudre…

4. Vue

4.1. Définition

C’est le conteneur qui parvient au client. Il contient et présente à l’utilisateur des informations, de manière organisée.

Dans le cas du web :

Schéma MVC au complet

crédits

4.2. Intérêts

Liste non exhaustive :

4.3. Fuites inévitables

On a parfois besoin de traitements dans les vues :

C’est comme ça.

4.4. Activité

4.4.1. Sans imbrication

On utilise la procédure view avec deux arguments seulement. Le HTML est directement envoyé au navigateur.

 

public function persos($display_type = 'html') {
    $mng = new PersonnagesManager();
    if ($display_type == 'html') {
        header("Content-Type:text/html");
        view('v_liste_persos.php', array('persos' => $mng->getList()));
    } else if ($display_type == 'csv') {
        header("Content-Type:text/plain");
        echo view('v_liste_persos_csv.php', array('persos' => $mng->getList()), true);
    } else {
        echo "Type inconnu.";
    }
}

Dans my.very.cute, seules ces lignes de la procédure view nous intéressent pour l’instant :

function view($view_file, $vars = array(), ...) {
    ...
    if (file_exists($view_file)) include($view_file);  // (1)
    else echo '<pre>'.print_r($vars, true).'</pre>';   // (2)
    ...
  1. Si le fichier de vue $view_file existe, on l’exécute. $vars contenant les données que le contrôleur passe à cette vue afin qu’elle les affiche.
  2. Sinon, on affiche le contenu de $vars (sorte d’outil de debug rustique).

Notez que si votre version de PHP le permet, il est possible d’utiliser <?= à la place de <? echo. C’est plus joli dans les vues.

4.4.2. Avec imbrication

On va utiliser le système de capture de sortie de PHP, pour pouvoir affecter en cette sortie (chaîne de caractère) à une variable et l’inclure dans une autre vue. On passe cette variable à la vue comme une vulgaire donnée, via le tableau $vars (deuxième paramètre de view).

$sous_vue = view('v_ma_vue.php', $vars, true)
view('v_page_globale.php', array('sous_vue' => $sous_vue))

Ou plus directement :

view('v_page_globale.php', array('sous_vue' => view('v_ma_vue.php', $vars, true))

Après avoir créé une v_page_globale.php, contenant du HTML valide (à base de <html>, <head>, <title>…), faîtes en sorte que toutes vos pages aient un logo et un pied de page.

4.5. Pour aller plus loin avec les vues

Il est possible d’utiliser des moteurs de vue plus évolués que celui défini dans la procédure view. Certains frameworks utilisent leur propre système, ou utilisent des projets dédiés au vues :

Après en avoir choisi un, intégrez-le à ce projet.

5. Approfondissement

5.1. Fuites

5.2. Organisation des fichiers

Plusieurs types d’arborescence sont possibles :

5.2.1. Un répertoire par concept

mvc
├── controlers
│   ├── add.php
│   └── list.php
├── models
│   ├── article.php
│   └── comment.php
└── views
    ├── article.php
    ├── footer.php
    ├── header.php
    └── menu.php

5.2.2. Un répertoire par module

mvc
├── main
│   ├── controlers
│   │   ├── add.php
│   │   └── list.php
│   ├── models
│   │   ├── article.php
│   │   └── comment.php
│   └── views
│       ├── article.php
│       ├── footer.php
│       ├── header.php
│       └── menu.php
└── wiki
    ├── controlers
    │   ├── add_page.php
    │   └── list_pages.php
    ├── models
    │   ├── comment.php
    │   └── page.php
    └── views
        ├── footer.php
        ├── header.php
        ├── menu.php
        └── page.php

5.2.3. Tout dans le même répertoire

Avec tout de même une convention pour s’y retrouver, comme dans l’activité où les modèles commencent par m_ et les vues par v_.

5.3. Liens intéressants vers MVC

5.4. Autres paradigmes d’architecture

5.5. Exemples de cadriciels

5.5.1. PHP

Pour les comparer : http://phpframeworks.com.

En bonus, quelques routeurs/dispatcheurs/répartiteurs :

5.5.2. Python

5.5.3. Javascript

5.5.4. Java

5.5.5. Listes




Monique Hervy et Christophe Gragnic, le 11/11/2014, 21h58'12".






Page générée le 04/12/2016, 10h08'07" (source).
historique de la page
historique global

 TogetherJS