Programmation PHP/Exemples/MVC
Historiquement, PHP est un langage glue, il peut être intégré avec le langage de balisage HTML. L'avantage est cette simplicité de mise-en-œuvre mais l'inconvénient est le mélange entre le traitement et l'affichage. Pour produire une application web claire et facile à entretenir, on peut séparer les différentes parties de l'application selon l'architecture Modèle-Vue-Contrôleur (ou MVC).
- Modélisation (Modèle : Partie métier spécifique à l'application)
- Visualisation (Vue : Partie visuelle de l'application)
- Contrôles (Contrôleur : Partie de gestion des événements de l'application)
De cette façon on peut implémenter son application en sous composantes ce qui augmente légèrement l'analyse de l'application mais fera gagner beaucoup de temps de développement par la suite. Cette architecture est déjà couramment employée dans les applications locales et les applications web l'utilise de plus en plus. On remarquera notamment que beaucoup de Cadriciel web sont basés sur ce principe.
Développement
modifier- Objectif : Faire un mini système de validation de données saisies.
Pour ce faire on a besoin :
- d'un formulaire HTML
- d'un module de validation
- d'un module de gestion homme-machine
- Pré-requis conseillés :
- html4
- php5
Création de la vue
modifierLa vue comprendra un formulaire HTML pour la saisie des données utilisateur :
<html>
<head>
</head>
<body>
<form id="fForm" name="fForm" action="" method="POST">
<!-- données utilisateur -->
<input type="text" id="iNom" name="iNom" /><br/>
<input type="text" id="iPrenom" name="iPrenom" /><br/>
<input type="text" id="iVisa" name="iVisa" /><p/>
<input type="submit" value="envoyer" />
</form>
</body>
</html>
Spécialisation des composantes
modifierIl est mieux de découper son application en sous composante. La vue par exemple pourrait contenir :
- le frameset de la page
- les containers à afficher
1. Le frameset (vueFrame.inc.php) :
<?php
$page['container']['frameSet'] = '
<html>
<head>'
.$page['css']
.$page['script'].
'</head>
<body>'
.$page['container']['header']
.$page['container']['main']
.$page['container']['footer'].
'</body>
</html>';
?>
2. Les formulaires deviendraient (vueFormulaire.inc.php) :
<?php
$page['container']['visa']='
<div id="cVisa">
<form id="fForm" name="fForm" action="" method="POST">
<!-- données utilisateur -->
<input type="text" id="iNom" name="iNom" value="'.$value['user']['nom'].'"/>
<span id="msgNom">'
// communication nom
.$msg['error']['nom'].'</span><br/>
<input type="text" id="iPrenom" name="iPrenom" value="'.$value['user']['prenom'].'"/>
<span id="msgPrenom">'
// communication prenom
.$msg['error']['prenom'].'</span><br/>
<input type="text" id="iVisa" name="iVisa" value="'.$value['user']['visa'].'"/>
<span id="msgVisa">'
// communication visa
.$msg['error']['visa'].'</span><p/>
<input type="submit" value="envoyer" />
</form>
</div>';
$page['container']['form1']='
<div id="">
<!-- autre formulaire -->
<form>
</form>
</div>';
?>
Création du modèle
modifierCette bibliothèque utilitaire reprendra les traitements de validation
On a besoin des fonctions suivantes :
- check des string alphabétiques
- check d'un numéro VISA (4 groupes de 4 chiffres avec le premier groupe commençant par 4 pour simplifier)
<?php
/* modeleValidation
SYNOPSIS : Cette bibliothèque reprend toutes les fonctions de validation de l'application
*/
/* isAlpha : contrôle de chaîne alphabétique
@author : nom
@date : 04.11.2007
@version : 1
*/
function isAlpha($str)
{// >((string)str)-(bool)>
return preg_match('/^([a-zA-Z]*)$/',$str);
}//
/* isVisa : contrôle de numéro VISA
@author : nom
@date : 04.11.2007
@version : 2
*/
function isVisa($str)
{// >((string)str)-(bool)>
return preg_match('/^(4)([0-9]{15})$/',$str);
}//
/* DEPRECIEE - isVisa : contrôle de numéro VISA
@author : nom
@date : 07.05.2006
@version : 1
function isVisa($str)
{// >((string)str)-(bool)>
return preg_match('/^([0-9]{16})$/',$str);
}//
*/
?>
! Ce modèle modeleValidation.inc.php par exemple comporte une nouvelle fonction isVisa remplaçant celle du 07.05.2006.
Création du contrôleur
modifierLe contrôleur regroupe les traitements de gestion de l'application, c'est à dire ici les événements déclenchés par l'utilisateur ou par le système. On parle souvent d'IHM, voilà un exemple.
On a besoin des contrôles suivants :
- validation de saisie
- affichage en fonction du statut de la saisie
<?php
/* controlAffichage
SYNOPSIS : Cette page reprend tous les contrôles pour gérer l'affichage
*/
# INIT
require_once "./Modele/modeleValidation.inc.php";
// var de contrôle de données saisies
$checkSum=3;
# CONTROL
if($_POST)
{
if(!isAlpha($_POST['iNom']))
{
$value['user']['nom'] = $_POST['iNom'];
$msg['error']['nom']='nom invalide !';
@$checkSum--;
}
if(!isAlpha($_POST['iPrenom']))
{
$value['user']['prenom'] = $_POST['iPrenom'];
$msg['error']['prenom']='prenom invalide !';
@$checkSum--;
}
if(!isVisa($_POST['iVisa']))
{
$value['user']['visa'] = $_POST['iVisa'];
$msg['error']['visa']='visa invalide !';
@$checkSum--;
}
}
# CHOIX DE L'OUTPUT
//if(!$checkSum)
if($checkSum==3)
{// formulaire validé
//$page['container']['main'] = 'Formulaire valide';
$msg['error']['alert'] = 'Formulaire valide';
}
else
{// formulaire invalide
//$page['container']['main'] = $page['container']['visa'].'<p> Formulaire invalide !</p>';*/
$msg['error']['alert'] = $page['container']['visa']
.'<p> Formulaire invalide !</p>';
}
?>
! utilisation de $page['container']['main'] ne sert a rien ici car sera écrasé dans l'appel de la page principale.
Gestion des containers
modifierChaque container ou div est ici considéré comme un flux à gérer. Ce qui permettra par la suite d'évoluer simplement vers l'ajax.
Pour bien construire sa page sans mauvaise surprise, il vaut mieux :
- charger les containers du plus petit enfant au plus grand parent
- ne faire l'output que du frameset
Par ex. :
<?php
// page principale
# INIT
@session_start();
# PREPARE PAGE
$page['container']['header']='ceci est le header<p/>';
$page['container']['footer']='ceci est le footer<p/>';
require_once "./Control/controlAffichage.inc.php";
require_once './Vue/vueFormulaire.inc.php';
// preparation du container principal
$page['container']['main']='
<div>Veuillez introduire vos données utilisateur :</div>'
.$page['container']['visa'];
require_once './Vue/vueFrame.inc.php';
# OUTPUT final
echo $page['container']['frameSet'];
?>
! d'abord $page['container']['main'] et en dernier $page['container']['frameSet']
! $page['container']['main'] de Control/controlAffichage.inc.php sera jamais affiché car il se fait écraser systématiquement avant ./Vue/vueFrame.inc.php' qui passe à l'affichage à proprement parler. Que faire?
Ajout de nouvelles fonctionnalités
modifierOn souhaiterait pouvoir gérer les communications dans plusieurs langues. Pour ce faire :
- on rajoute un modele messageList.inc.php
- on modifie un peu le contrôleur
- on crée ou modifie les composantes de la vue
1. messageList.inc.php
<?php
/* messageList
SYNOPSIS : Cette liste reprend toutes les communications usuelles
NOTA : Il est préférable d'en faire une table dans une DB
pour décharger la RAM du serveur et de créer la fonction d'appel du message
*/
// par convention 1=fr et 2=uk
# ERRORS
$msg['error']['alpha'][1] = 'champ alpha invalide';
$msg['error']['alpha'][2] = 'invalid alpha field';
$msg['error']['num'][1] = 'champ numérique invalide';
$msg['error']['num'][2] = 'invalid numeric field';
$msg['error']['invalid'][1] = 'formulaire invalide !';
$msg['error']['invalid'][2] = 'invalid form !';
# SUCCESS
$msg['success']['valid'][1] = 'le formulaire a été validé';
$msg['success']['valid'][2] = 'the form has been validated';
# MESSAGE
$msg['communication']['form'][1] = 'veuillez introduire vos données utilisateur';
$msg['communication']['form'][2] = 'please introduce your user data';
?>
2. controlAffichage.inc.php devient
<?php
/* controlAffichage
SYNOPSIS : Cette page reprend tous les contrôles pour gérer l'affichage
*/
# INIT
require_once "./Modele/modeleValidation.inc.php";
require_once "./Modele/messageList.inc.php";
// var de controle de données saisies
$_SESSION['checkSum']=3;
# CONTROL
if($_POST)
{
if(!isAlpha($_POST['iNom']))
{
$value['user']['nom'] = $_POST['iNom'];
$msg['error']['nom']= $msg['error']['alpha'][$lang]; // <--
@$_SESSION['checkSum']--;
}
if(!isAlpha($_POST['iPrenom']))
{
$value['user']['prenom'] = $_POST['iPrenom'];
$msg['error']['prenom']= $msg['error']['alpha'][$lang]; // <--
@$_SESSION['checkSum']--;
}
if(!isVisa($_POST['iVisa']))
{
$value['user']['visa'] = $_POST['iVisa'];
$msg['error']['visa']= $msg['error']['num'][$lang]; // <--
@$_SESSION['checkSum']--;
}
}
if($_SESSION['checkSum']==3)
{// formulaire validé
$page['container']['main'] = $msg['success']['valid'][$lang]; // <--
}
else
{// formulaire invalide
$page['container']['main'] .= $page['container']['visa'] // <--
.'<p>'.$msg['error']['invalid'][$lang].'</p>'; // <--
}
?>
3. ici rien est à faire
Application
modifierL'application se construit ensuite par inclusion des composantes
<?php
// Main page
# INIT
@session_start();
// preparation de la langue choisie (fr par defaut)
$lang = $_GET['lang']?$_GET['lang']:1;
# PREPARE PAGE
$page['container']['header']='ceci est le header<p/>';
$page['container']['footer']='ceci est le footer<p/>';
// appel de controlAffichage
// page['container']['main'] va etre remplace si le formulaire est valide
require_once "./Control/controlAffichage.inc.php";
require_once './Vue/vueFormulaire.inc.php';
#region[1] mainPage
// preparation du container principal
$page['container']['main']='
<div><a href="'.$_SERVER['PHP_SELF'].'?lang=1">fr</a> | <a href="'.$_SERVER['PHP_SELF'].'?lang=2">uk</a></div><p/>
<div>'.$msg['communication']['form'][$lang].'</div>'
.$page['container']['visa'];
require_once './Vue/vueFrame.inc.php';
#endRegion[1]
# OUTPUT final
echo $page['container']['frameSet'];
?>
! Il y a encore moyen d'optimiser la region[1] pour ne pas avoir à initialiser le container main avant l'inclusion et de faire de controlAffichage.inc.php un contrôleur ne comprenant aucun autre traitement que l'appel pour affichage.
En bref
modifierCette façon de programmer permet de construire des applications plus souples et évolutives et ne demande pas plus de méthode que celle de choisir correctement ses variables lors de l'analyse. L'utilisation de classes permet d'optimiser plus encore le développement et faciliter l'ergonomie.
Il existe de nombreuses implémentations de MVC dans des cadriciels web écrit en PHP.