Dernière discussion page 36 sur MVC et le rôle de chacun des composants
-----------
Post initial
Model View Controller
Introduction
92.3% (estimation à la con) des applis PHP sont consitués de plusieurs scripts, dans lesquels sont mélangés accès aux données, logique métier (business ou domain logic) et présentation. On le voit surtout ici, où souvent les requêtes SQL et la génération d'HTML se côtoient. Or, ça va strictement à l'encontre de l'un des fondement de la programmation : la séparation des couches. Dans un monde idéal, on aurait trois couche : une qui s'occupe de l'accès aux données et de la logique métier (model), une qui s'occupe de la présentation (view), et une dernière qui coordonne le tout en gérant ce que l'utilisateur fabrique (controller).
Rôle et fonctionnement de chaque couche
Model :
Le model va donc contenir tout la business logic et l'accès aux données. Il doit être indépendant des autres couche, et il ne doit même pas savoir qu'il est utilisé dans un MVC.
Un exemple de model tout simple serait :
class UserModel {
function add_user($user_name, $user_age) {
mysql_query("INSERT INTO user VALUES($user_name, $user_age)" );
}
function get_user($user_id) {
return mysql_fetch_assoc(mysql_query("SELECT * FROM user WHERE user_id = $user_id" ));
}
function get_average_age() {
// Bordel qui calcul la moyenne d'âge et qui la retourne
}
function list_users() {
// Retourne un tableau avec toute la liste des users
}
} |
Note : cet exemple est tout simple, buggé, faillé, dépendant de la source de données, mais illustre à peu-près le truc.
View :
La vue récupère les données à partir du model, et s'occupe de les afficher. Le controller va donc instancier la bonne view, lui filer le model, et la vue va s'occuper de récupérer ce qu'elle veux.
Du genre :
class UserListView {
var $user_model;
function UserListView($user_model) {
$this->user_model = $user_model;
}
function render() {
echo '<table summary="user list">'
$user_list = $this->user_model->list_users();
foreach($user_list as $user) {
echo '<tr><td>', $user['name'], '</td><td>', $user['age'], '</td></tr>';
}
echo '</table>';
}
} |
Note : en pratique, on utilisera un système de template genre Smarty ou XSLT
Controller :
Lui va s'occuper de gérer ce que l'utilisateur demande, va instancier le model et la bonne vue, puis gérer tout ça.
Exemple :
class UserController {
function run() {
switch($_GET['action']) {
case 'add':
$model = new UserModel();
$model->add_user($_POST['name'], $_POST['age']);
$view = new UserAddedView($model); // Vue lorsqu'un utilisateur a été ajouté
$view->render();
break;
case 'list':
$model = new UserModel();
$view = new UserListView($model);
$view->render();
break;
}
}
} |
Note : exemple faillé et buggé, mais illustrant le truc de façon simple
Implémentation
Ce sera un peu le but de ce topic. MVC est plus un concept qu'une Design Pattern précise, les implémentations peuvent être différentes. Les exemples que j'ai donné ne sont qu'une implémentation possible.
Pour la view, on peut utiliser un truc comme dans l'exemple, ou passer par une template view (Smarty), ou une transform view (XSLT). Pour le controller, soit un switch comme dans l'exemple, mais très vite lourdingue, soit par un command pattern, où une action et une vue sont associée dans un objet Command... Pour le model, soit une classe qui mappe un objet (ici notre User), soit tout une table, avec là-dessus des DAO ou des DataMappers pour l'accès à la source de données...
Bien ! En espérant de pas avoir fait trop d'erreurs, je vais lancer ce topic avec mon implémentation à moi en cours de design. Donc ce que j'ai commencé, c'est niveau accès aux données. J'ai designer 3 Dao réutilisables par les model : TableDao, OrderedTableDao et HierarchyTableDao. Le premier est utilisé pour une table tout simple, avec des méthodes d'ajout, de modification, de listage, etc. Le suivant est là pour les tables dont les enregistrements sont ordonnés (pensez à une liste de rubrique, donc on doit pouvoir modifier l'ordre d'affichage). Le dernier est là pour les données hiérarchisées (liste de rubriques hiérarchisée avec liste d'articles dans chaque rubrique).
Les trois classes sont abstraites, va falloir en fournir une implémentation pour chaque source de données (MySql, XML, etc.). L'objectif est évidemment de pouvoir changer de source de données à la volée, tout en prenant en compte les différences (des données hiérarchisées ne seront pas représentées de la même manière dans une base MySql que dans un fichier XML).
Voici mon diagramme UML :
Bon, reste à designer les model, les controllers et les view . Pour les view, j'ai opté pour des templates XSLT... Va falloir un espèce de "XmlBinder" qui prend un model et le transforme en XML compréhensible par l'XSLT. Pour le controller, ça j'ai pas encore trop réfléchit
Donc à votre tour aussi de poser vos questions, d'exposer vos point de vue, de présenter votre implémentation etc...
Lectures intéressantes :