Accueil du site > INFORMATIQUE > PHP > Motifs de Conception > Motif Modele Vue Controleur et PHP

Traduction d’un article de Harry Fuecks sur phpPatterns, 02.12.2002

Motif Modele Vue Controleur et PHP

2 - MVC Version 2

mardi 18 avril 2006, par Thierry Bothorel

Toutes les versions de cet article : [English ] [français ]

L’article original MVC Pattern (Version 2) ne proposait que le nouveau code exemple à télécharger. J’y rajouterai le code des deux classes modifiées View et Controller (les deux autres Model et DataAccess n’ayant pas changé) et, bien sûr, quelques-uns des commentaires d’origine.

Voici une version mise à jour du motif Modèle Vue Contrôleur qui adhère plus strictement à la définition de ce motif.

La première version de ce motif peut être trouvée ici. Grâce à des commentaires constructifs, je l’ai modifié pour être plus proche de la définition généralement admise du motif MVC. Cet article met à jour le code tout en laissant l’ancien article pour donner un aperçu du concept.

En aparté, j’ai découvert Phrame aujourd’hui : un portage du projet Jakarta Struts à PHP qui fournit d’excellents outils pour réussir à séparer le Modèle et la Vue (couplage lâche).

Le nouveau diagramme UML :

GIF - 5.3 ko
MVC révisé

Pour le reste, je laisserai le code parler par lui-même pour qu’on puisse passer à autre chose…

Ressources

Jason E.Sweat a fait un excellent travail pour expliquer MVC dans l’édition Mai 2003 de la revue php


ProductController.php

<?php
/**
*  Controle le flux de l'application
*/
class ProductController {
    var
$model;
    var
$view;

    
//! Un constructeur.
    /**
    * Construit un nouvel objet ProductController

    * @param object $dao une instance de la classe DataAccess
    */
    
function ProductController (& $dao) {
        
$this->model=& new ProductModel($dao);
    }
}

class
ProductItemController extends ProductController {
   
//! Un constructeur.
    /**
    * Construit un nouvel objet ProductItemController
    *
    * @param object $dao une instance de la classe DataAccess
    * @param array $getvars variables HTTP GET reçues
    */
    
function ProductItemController (& $dao,$getvars=null) {
        
ProductController::ProductController($dao);
        
$this->view=& new ProductItemView($this->model,$getvars['id']);
    }

    function &
getView () {
        return
$this->view;
    }
}

class
ProductTableController extends ProductController {
   
//! Un constructeur.
    /**
    * Construit un nouvel objet ProductTableController
    *
    * @param object $dao une instance de la classe DataAccess
    * @param array $getvars variables HTTP GET reçues
    */
    
function ProductTableController (& $dao,$getvars=null) {
        
ProductController::ProductController($dao);
        if ( !isset (
$getvars['rowsperpage']) )
            
$rowsperpage=20;
        if ( !isset (
$getvars['rownum']) )
            
$getvars['rownum']=0;
        
$this->view=& new ProductTableView($this->model,
                                    
$rowsperpage,
                                    
$getvars['rownum']);
    }

    function &
getView () {
        return
$this->view;
    }
}
?>

ProductView.php

<?php
/**
*  Lie les données d'un Produit à la génération du HTML
*/
class ProductView {
    
/**
    * Une instance de la classe ProductModel
    *
    * @access private
    * @var object
    */
    
var $model;

    
/**
    * Le code HTML généré est stocké ici pour affichage
    *
    * @access private
    * @var string
    */
    
var $output;

    
//! Un constructeur.
    /**
    * Construit un nouvel objet ProductView
    *
    * @param object $model une instance de la classe ProductModel
    */
    
function ProductView (&$model) {
        
$this->model=& $model;
    }

    
//! Un manipulateur
    /**
    * Crée le haut d'une page HTML
    *
    * @return void
    */
    
function header () {
        
$this->output=<<<EOD
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Nos Produits </title>
<style>
body
{ font-size: 13.75px; font-family: verdana }
td
{ font-size: 13.75px; font-family: verdana }
.title
{ font-size: 15.75px; font-weight: bold; font-family: verdana }
.heading
{
    font-size: 13.75px; font-weight: bold;
    font-family: verdana; background-color: #f7f8f9
}
.nav
{ background-color: #f7f8f9 }
</style>
</head>
<body>
<div align="center" class="title">Nos Produits</div>
EOD;
        
$this->output.="\n<div align=\"right\"><a href=\"".
            
$_SERVER['PHP_SELF']."\">D&eacute;but</a></div>\n";

    }

    
//! Un manipulateur
    /**
    * Crée le bas d'une page HTML
    *
    * @return void
    */
    
function footer () {
        
$this->output.="</body>\n</html>";
    }
}

class
ProductItemView extends ProductView {
    
/**
    * ID du produit à afficher
    *
    * @access  private
    * @var int
    */
    
var $productID;

    
//! Un constructeur
    /**
    * Construit un nouvel objet ProductView
    *
    * @param object $model instance de la classe ProductModel
    */
    
function ProductItemView (&$model,$productID) {
        
ProductView::ProductView($model);
        
$this->productID=$productID;
    }

    
//! Un manipulateur
    /**
    * Affiche un produit unique
    *
    * @return void
    */
    
function productItem() {
        
$this->model->listProduct($this->productID);
        while (
$product=$this->model->getProduct() ) {
            
$this->output.="<p><b>Nom</b>:".$product['PRODUCTNAME']."</p>".
                
"<p><b>Prix</b>:".$product['UNITPRICE']."</p>".
                
"<p><b># en stock</b>:".$product['UNITSINSTOCK']."</p>";
            if (
$this->$product['DISCONTINUED']==1 ) {
                
$this->output.="<p>Ce produit n'est plus commercialis&eacute;.</p>";
            }
        }
    }

    
//! An accesseur
    /**
    * Retourne le code HTML généré
    *
    * @return string
    */
    
function toString () {
        
$this->header();
        
$this->productItem();
        
$this->footer();
        return
$this->output;
    }
}

class
ProductTableView extends ProductView {
    
/**
    * nombre de résultats par page
    *
    * @access private
    * @var int
    */
    
var $rowsPerPage;
    
/**
    * ID de l'enregistrement à partir duquel commencer l'affichage
    *
    * @access private
    * @var string
    */
    
var $rowNum;

    
//! Un constructeur.
    /**
    * Construit un nouvel objet ProductView
    *
    * @param object $model instance de la classe ProductModel
    */
    
function ProductTableView (&$model,$rowsPerPage=20,$rowNum=0) {
        
ProductView::ProductView($model);
        
$this->rowsPerPage=$rowsPerPage;
        
$this->rowNum=$rowNum;
    }

    
//! Un manipulateur
    /**
    * Crée une table (HTML) de produits
    *
    * @return void
    */
    
function productTable() {
        
$this->model->listProducts($this->rowNum,$this->rowsPerPage);
        
$this->output.="<table width=\"600\" align=\"center\">\n<tr>\n".
                
"<td class=\"heading\">D&eacute;signation</td>\n".
                
"<td class=\"heading\">Prix</td>\n</tr>\n";
        while (
$product=$this->model->getProduct() ) {
            
$lastID=$product['PRODUCTID'];
            
$this->output.="<tr>\n<td><a href=\"".$_SERVER['PHP_SELF'].
                
"?view=product&id=".$product['PRODUCTID']."\">".
                
$product['PRODUCTNAME']."</a></td>".
                
"<td>".$product['UNITPRICE']."</td>\n</tr>\n";
        }
        
$this->output.="<tr class=\"nav\">\n";
        if (
$this->rowNum > 0 && $this->rowNum > $this->rowsPerPage ) {
            
$this->output.="<td><a href=\"".$_SERVER['PHP_SELF'].
                
"?view=table&rownum=".($this->rowNum-$this->rowsPerPage).
                
"\"><< Prev</a></td>";
        } else {
            
$this->output.="<td>&nbsp;</td>";            
        }
        if (
$this->rowsPerPage <= ( $lastID - $this->rowNum ) ) {
            
$this->output.="<td><a href=\"".$_SERVER['PHP_SELF'].
                
"?view=table&rownum=".($this->rowNum+$this->rowsPerPage).
                
"\">Next >></a></td>";
        } else {
            
$this->output.="<td>&nbsp;</td>\n";            
        }
        
$this->output.="</tr>\n</table>\n";
    }

    
//! Un accesseur
    /**
    * Retourne le code HTML généré
    *
    * @return string
    */
    
function toString () {
        
$this->header();
        
$this->productTable();
        
$this->footer();
        return
$this->output;
    }
}
?>

et finalement le contrôleur principal revisité, index.php :

error_reporting(E_ALL ^ E_NOTICE);
require_once('lib/DataAccess.php');
require_once('lib/ProductModel.php');
require_once('lib/ProductView.php');
require_once('lib/ProductController.php');
$dao=& new DataAccess ('localhost','root','password','mvc2');
switch ( $_GET['view'] ) {
    case "product":
        $controller=& new ProductItemController($dao,$_GET);
        break;
    default:
        $controller=& new ProductTableController($dao,$_GET);
        break;
}
$view=$controller->getView();
echo ("<pre>" );
// print_r($controller);
echo ("</pre>" );
echo ($view->toString());

Documents joints

  • Code MVC Version 2 Code MVC Version 2 (Zip – 12.9 ko)

Répondre à cet article | RétroLiens :0


Répondre à cet article