Cet article fait suite à celui-ci :
Partie 1 - Pourquoi utiliser un framework MVC
Je vais vous présenter ici la base du début du commencement d'un bon contrôleur dans une optique MVC.
Tout d'abord, un peu de théorie. Selon wikipedia "Le contrôleur prend en charge la gestion des évènements de synchronisation pour mettre à jour la vue ou le modèle et les synchroniser.".
Ce qui signifie que le contrôleur est appelé à chaque évènement lié à l'utilisateur (en tout cas dans le web). Il va ensuite synchroniser la vue et le modèle en fonction de la requète. Attention cependant, si le contrôleur est le "système nerveux" du programme, il n'est pas le cerveau. En effet, l'ensemble des classes "métiers" nécessaires au traitement des informations seront à l'extérieur du MVC, et seront appelées si besoin par le contrôleur.
Au final, le contrôleur est le coordinateur de notre programme. Ce qui signifie que tout commence par lui et tout fini par lui (en tout cas, d'un point de vue extérieur au framework).
Chronologiquement, le framework va analyser la requète, puis va déterminer :
- Le contrôleur à utiliser
- L'action à appelée
- Les paramètres supplémentaires.
Le couple contrôleur/action se cherchera de coordonner les différents acteurs pour finir (en général) par l'envoi de la vue.
Par exemple, voici un contrôleur et quelques actions typiques pour gérer les utilisateurs d'un espace membre.
class userController {
// On va détailler un peu cette action
function register() {
// On attend ici dans les paramètres le pseudo et le pass du user
if (empty($this->params['pseudo'] || empty($this->params['pass'])) {
$this->render_view('formulaire_incomplet.tpl');
} else {
// on insere
$user = new User($this->params['pseudo'], $this->params['pass'] );
if ($user) {
$this->render_view('inser_user_success.tpl');
} else {
$this->render_view('inser_user_failed.tpl');
}
}
}
function update() {
// On attend ici en paramètre l'id du user à modifier et le pseudo et/ou pass à modifier
}
function delete() {
// On attend ici l'id du user à supprimer
}
function login() {
// On attend ici l'id du user à connecter
}
function logout() {
// On attend ici l'id du user à déconnecter
}
}
La jonction formulaire <-> base de donnée est la partie la plus redondante, la plus pénible et la plus grande source d'erreur de tout programme web. Le but du contrôleur est de simplifier et centraliser tout ça.
Parlons justement de centralisation.
Jusqu'ici, hormis ressembler les fonctions, on a pas encore grand chose. On a déjà vaguement aperçu le modèle User, ainsi que la méthode $this->render_view encore inconnue.
Concentrons nous sur ce qu'il y a à rassembler pour que notre classe contienne TOUT ce dont elle a besoin:
- Le modèle
- La vue
- La session
- Les paramètres d'entrées
class userController {
private $db;
private $view;
private $session;
private $params;
// Lié au fonctionnement
private $data;
public __construct() {}
public register() {}
public update() {}
public delete() {}
public login() {}
public logout() {}
// Nouvelle méthode, vu au paragraphe avant, qui serivra à afficher une vue
private render_view() {}
}
Dans ces quelques lignes, il y a toute l'architecture de notre espace membre. Toutes les variables extérieures sont accessibles à chaque action. Reste maintenant à alimenter ces variables, et à rendre nos actions appelables par un visiteur.
Mais avant tout, regardons de plus prêt notre classe. Nous l'avons créée pour gérer un espace membre, or un site n'est jamais constitué de si peu. Il va nous falloir utiliser d'autres contrôleurs pour les autres contextes, par exemple sur une galerie d'images, il nous faudra gérer les images.
Pour cela nous allons créer un contrôleur imageController qui devra lui aussi utiliser les sessions, les paramètres, les vues, etc. Grâce à l'héritage, nous allons pouvoir créer une classe Controller mère dont chaque controller héritera. Cette classe mère se chargera des variables et méthodes communes. Ainsi, nous aurons :
abstract class Controller {
/**
* Notre modèle
*/
protected $db;
/**
* Notre vue
*/
protected $view;
/**
* La session
*/
protected $session;
/**
* Les paramètres POST et GET
*/
protected $params;
/**
* Un tableau qui contiendra se qu'on enverra à la vue.
* La vue ne disposera que de ces données et aucune autre
*/
protected $data;
/**
* Constructeur
*/
public function __construct() {}
/**
* Méthode privée appelée par chaque action et qui se chargera de la vue.
*/
protected function render_view() {}
}
Ce qui permet de simplifier notre contrôleur :
class userController extends Controller{
public register() {}
public update() {}
public delete() {}
public login() {
// Notre vue n'étant pas encore écrite, nous utiliserons un simple echo
echo 'Hello World';
}
public logout() {}
}
Testons maintenant notre contrôleur. Il faut pour cela avoir un moyen pour se diriger vers le bon couple contrôleur/action en fonction de la requète. Nous ferons très simple pour commencer :
Placer ceci dans un fichier index.php
// La classe abstraite
require_once 'controller.php';
// Notre controleur user
require_once 'userController.php';
if (isset($_GET['controller'])) {
$controller = $_GET['controller'];
} else {
// On peut mettre un contrôleur par défaut
}
if (isset($_GET['action'])) {
$action = $_GET['action'];
} else {
// On peut mettre une action par défaut
}
$oController = new $controller;
$oController->$action;
Il vous reste à appeler l'adresse correspondante, par exemple en local, si les fichiers sont dans le répertoire framework, nous appelerons http://localhost/framework/index.php?controller=user&action=login
Cette partie est maintenant finie. Nous verrons dans la prochaine partie la réécriture des urls car il est clair qu'une url comme celle du dessus n'est pas très sexy sur un site sérieux. Nous verrons aussi, dans les différents articles qui suivront, comment améliorer nettement la classe abstraite par l'ajout de nombreuses fonctionnalités, notamment la pagination, les filtres, le cache, etc...
Aller à la partie 3