Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Programmation en PHP - Développement selon l'approche MVC : Modèle - Vue - Contrôleur - Le retour - Théorie,
Par rawsrc

Le , par rawsrc

0PARTAGES

Salut les développeurs,

aujourd'hui je vais vous faire un billet pour démystifier le concept de programmation en PHP avec l'approche Modèle-Vue-Contrôleur (MVC pour les intimes).

Compte tenu que les applications web ont une fâcheuse tendance de nos jours à l'embonpoint voire à l'obésité , il est important d'organiser le code source de manière à pouvoir faciliter d'une part le développement de nouvelles fonctionnalités et d'autre part, la maintenance du code existant. Dans cette optique, l'expérience a montré qu'il était tout à fait possible de séparer le code source en trois parties distinctes relatives à chaque aspect des traitements :

  • Le modèle qui regroupe tout ce qui est relatif au métier (aspects professionnels de l'application)
  • La vue qui regroupe tout ce qui est relatif au rendu
  • Le contrôleur qui regroupe tout ce qui est relatif aux entrées/contrôle du flux/sorties de l'application


Je pars d'une approche rigide pour bien poser le concept général. Avec l'expérience, il vous sera possible d'assouplir un peu cette approche, mais pour l'instant aucun écart ne vous sera profitable sauf à vous embrouiller.

LE MODÈLE

Comme précisé plus haut, cet aspect regroupe tout ce qui est propre à la couche métier de l'application.
Par couche métier, il faut bien comprendre que cela correspond à la valeur ajoutée de l'application.
Quand vous travaillez par exemple sur une application de gestion, la couche métier va englober la gestion des comptes (création, modification, suppression...), catégories, calculs des soldes selon les règles en vigueur, gestion des arrondis, éditions, etc.
D'une application à l'autre, vous allez très vite vous rendre compte que certains aspects métiers sont communs et réutilisables : connexion à un compte, déconnexion, accès à une base de données (PDO)...
Ainsi, vous allez très probablement vous poser la question du meilleur moyen pour réutiliser très facilement le code entre applications et vous allez inévitablement tomber sur la Programmation Orientée Objet (POO) conçue avec cette idée de portabilité dès le début. Je privilégierai cette approche dans ce billet.

LA VUE

Cet élément doit être pris au sens large du concept, par exemple les éléments de cette liste relèvent de la vue :
  • générer du html
  • générer du xml
  • générer un pdf
  • etc.

Il faut bien comprendre que la vue est une terminaison dans le traitement. La vue est une fin, elle ne doit s'occuper que de bien générer de manière autonome (le plus possible) un élément qui devra être envoyé au navigateur.
Plus clairement : la vue est passive, il faut lui passer en paramètre tous les éléments nécessaires à son travail de génération. Cela implique qu'avant d'appeler la vue, il faut au préalable que le traitement en cours collecte exhaustivement valeurs, variables et autres données qui seront utilisées au moment de la génération du rendu.
Une vue ne doit avoir à sa disposition qu'un accès très limité aux autres parties de l'application. En conséquence, les seules fonctions auxquelles elle peut accéder ne doivent avoir trait qu'à la vue par exemple une fonction d'échappement des caractères dangereux, une fonction de mise en forme de texte...
En aucun cas, elle ne doit faire appel à la couche métier ou au contrôleur.

LE CONTRÔLEUR

C'est le chef d'orchestre du trio, il est le point d'entrée de chaque traitement, il pilote le déroulé du programme (le flux de traitement), appelle les éléments de la couche métier, collecte les données de réponse, appelle les éléments de vue et envoie une réponse au navigateur à la toute fin du traitement.

Ici, il y a un point très important à saisir c'est la notion de point d'entrée de chaque traitement.
Il faut bien percevoir qu'interagir avec une application web est équivalent à l'accomplissement d'une suite d'actions.

Une action va correspondre par exemple à :
  • demander l'affichage d'une page web
  • appeler un formulaire de saisie
  • soumettre un formulaire rempli
  • demander la génération d'un document pdf
  • récupérer des données au format xml
  • trier les données d'un tableau sur clic d'un en-tête de colonne
  • changer de page sur clic d'un élément de pagination
  • etc.

Conformément au principe ci-dessus,
A CHAQUE ACTION DISPONIBLE DANS LE SITE WEB DEVRA CORRESPONDRE UN SEUL ET UNIQUE CONTRÔLEUR QUI SERA DE FAIT L'UNIQUE POINT D'ENTRÉE DE L'APPLICATION POUR CE TRAITEMENT

Ne vous inquiétez pas, sur les sites web d'une certaine taille, il n'est pas rare de trouver plus 1 000 contrôleurs... qui correspondent à 1 000 actions possibles sur le site...

REQUÊTE SERVEUR

Comme vous n'êtes pas sans le savoir , le navigateur ne dispose que d'un seul et unique moyen pour communiquer avec un serveur web : l'URL.
Afin que le serveur web soit à même de différencier les actions et de ne pas s'emmêler les pinceaux, il sera obligatoire d'avoir une correspondance unique entre URL et action.
En conséquence,
A CHAQUE ACTION DISPONIBLE DANS LE SITE WEB DEVRA CORRESPONDRE UNE SEULE ET UNIQUE URL QUI SERA DE FAIT L'UNIQUE POINT D'ENTRÉE DU SITE POUR CE TRAITEMENT

ORGANISATION DU CODE SOURCE

Depuis le début, je vous parle de la notion de point d'entrée, il est essentiel de bien la comprendre, car cela va directement influer sur la manière d'organiser le code source d'une application.
Un serveur web tire son nom du fait qu'il n'a que pour seule et unique tâche de servir des réponses à des requêtes qu'il reçoit. Pour y parvenir, il exécute des scripts avec du code source que vous avez pris grand soin d'écrire.

Maintenant, abordons un aspect plus technique : l'environnement d’exécution PHP a une particularité qui est à la fois une force et une faiblesse : PHP est dit "stateless", ce qui veut tout simplement dire qu'il ne garde rien en mémoire entre chaque requête.
C'est exactement comme s'il s'éteignait et se rallumait entre chaque appel. Comme si vous redémarriez votre ordinateur entre chaque appui de touche au clavier, c'est embêtant, non ? Bah pas tant que ça !

La force réside dans le fait que l'environnement d'exécution est tout neuf et propre à chaque nouveau traitement, la faiblesse c'est que l'environnement d'exécution spécifique à votre application est détruit à chaque fin de traitement.
Par environnement spécifique à votre application, il faut comprendre que cela correspond à votre connexion à la base de données, la définition de constantes utilisées partout dans le code, certains paramétrages d'exécution, la manière de charger des classes, etc.
Bref, c'est tout le socle commun et nécessaire et à la bonne exécution de votre code qui est supprimé de la mémoire une fois la réponse du serveur envoyée.

Comme à chaque nouvelle requête cet environnement devra être reconstruit, il est nécessaire de bien réfléchir à la manière d'organiser son code afin que ce redémarrage ne soit pas une torture insupportable.

On va voir qu'il existe deux manières d'appréhender la problématique, sauf qu'il ne faut en garder qu'une seule à la fin

En simplifiant, dans la configuration d'un serveur web, il est explicitement défini un répertoire racine (généralement /www/) qui va servir à enregistrer tous les fichiers relatifs à votre application (.php, .jpeg, .css, .js, etc.) Il est également possible de créer autant de sous-répertoires que nécessaire afin de faciliter l'organisation de votre code.

MULTIPLES POINTS D'ENTRÉE SUR LE SITE

Comme nous l'avons vu, un serveur web ne fait simplement que correspondre une URL (côté navigateur) à une ressource (au sens abstrait) disponible sur ledit serveur (dans le système de fichiers sur le disque dur).
Dans une approche décentralisée, il y a une correspondance directe entre :

Votre application démarrera directement dans le fichier situé dans /abc/def/fichier.php Pourquoi pas, me direz-vous ? OK, poussons plus en avant la logique.

Votre application démarrera directement dans le fichier situé dans /abc/def/ghi/jkl/mno/login.php

Maintenant, revenons à nos moutons : votre application a besoin d'un environnement d'exécution spécifique pour que tout le code source puisse être exécuté sans problème.
Donc pour reconstruire cet environnement et comme vous êtes un développeur sensé vous allez probablement créer un répertoire dans votre arborescence sous /www/bootstrap/ afin d'y loger tous les scripts d'initialisation : PDO, constantes, autoloader, durée d'exécution max, etc.
Le hic c'est qu'à chaque nouveau script, vous allez devoir jongler avec les require_once __DIR_.'/../../../../bootstrap/PDO.php; le nombre de /../, c'est 3 ou 4 ?
Ça sera pareil quand il s'agira d'inclure les fichiers du modèle pour bâtir une réponse...
Ça sera très vite ingérable et sacrément gonflant, croyez-moi et vous allez finir par vous maudire ainsi que vos descendants sur des générations et des générations

UNIQUE POINT D'ENTRÉE SUR LE SITE

L'autre approche, dite centralisée, va permettre de vous faciliter grandement la vie et de bénéficier d'un système très vite opérationnel et sans avoir à fournir trop d'efforts.
On va poser le principe que toutes les requêtes arrivant sur le serveur soient redirigées sur un unique point d'entrée, un fichier PHP, appelé, attention ! Roulements de tambour : index.php. Bon vous me direz quelle folie, hein !?!! M'enfin de temps en temps...
Donc comme ce fichier va récupérer absolument toutes les requêtes, il va nous être très facile de procéder à l'amorçage de notre environnement d'exécution.
Plus de gymnastique douloureuse, juste en début de fichier un simple include 'bootstrap/PDO.php'; suivi de la suite des fichiers nécessaires au démarrage.
Et ce qui n'est pas négligeable, c'est que comme vous êtes à la racine de votre site, il est très facile de créer une constante qui contient le chemin physique de la racine du site sur le serveur, le classique define('DIR_ROOT', __DIR__.DIRECTORY_SEPARATOR);.

Pour parvenir à ce résultat : 2 voies possibles : soit vous configurez le serveur web afin que lui se charge d'effectuer la redirection (ma solution préférée), soit vous codez toutes vos URL de manière à forcer la redirection quelque chose dans le genre : http://www.monsite.fr/index.php?page=login ou http://www.monsite.fr/index.php?page=loginsubmit.

Comme les URL sont dé-corrélées de la structure des répertoires et des fichiers sur le disque dur, la contrepartie de cette approche c'est qu'il va falloir disposer d'un système interne à l'application qui va être capable d'identifier quel fichier PHP exécuter pour chaque URL reçue.



Un petit aparté s'impose, comme le vocabulaire est très important dès qu'il s'agit de technique, il faut bien noter ceci :


Quand vous êtes dans un navigateur (Firefox, Chrome, Opéra, Safari...), vous allez parler d'URL, mais quand vous allez vous placer du côté du serveur web, vous allez parler de ROUTE. La distinction est subtile, mais importante : une route est une URL qui a été analysée. C'est-à-dire que l'URL a été entièrement parsée afin d'extraire tous les composants séparément selon la norme RFC3986.

Une fois que les éléments constitutifs d'une URL sont connus, une application web va devoir les comparer avec son paramétrage interne afin d'essayer de trouver si elle dispose des ressources adéquates pour être en mesure de construire une réponse appropriée et de l'envoyer au navigateur client. Cette étape essentielle s'appelle le ROUTAGE et s'appuie sur une ou plusieurs table de routage. Si aucune route ne correspond à l'URL alors l'application enverra une réponse de type Error 404.

Dans nos exemples, une table de routage indiquerait que :
- quand page = "login" alors il faut aller transférer le flux de traitement à \Utilisateur\Controller\Login.php,
- quand page = "loginsubmit" alors il faut aller transférer le flux de traitement à \Utilisateur\Controller\LoginSubmit.php,

Maintenant nous pouvons compléter les assertions du début :

A CHAQUE ACTION DISPONIBLE DANS LE SITE WEB DEVRA CORRESPONDRE UN SEUL ET UNIQUE URL/ROUTE/CONTRÔLEUR QUI SERA DE FAIT L'UNIQUE POINT D'ENTRÉE DU SITE POUR CE TRAITEMENT

Pour résumer schématiquement :
Simple, non ?




L'énorme avantage de l'approche centralisée, c'est qu'il n'y a plus aucune exposition de votre arborescence partielle du disque dur sur le web.
Par ailleurs, avec ce système, il vous sera tout à fait possible d'utiliser des URL personnalisées à souhait pour peu que vous ayez un système de routage souple.

Nous arrivons à la fin de l'exposé théorique du concept MVC.

Dans un autre billet de blog, je vais coder entièrement un cas pratique afin d'exposer la mise en oeuvre de ce concept abstrait, mais fort pratique. Pour cela, je n'utiliserai que la Programmation Orientée Objet (d'une manière simple) et vous verrez ainsi comment tout cela se met en application.

Bon code à tous

rawsrc

Une erreur dans cette actualité ? Signalez-le nous !