Accueil du site > INFORMATIQUE > PHP > Motifs de Conception > Model View Controller Pattern and PHP

Translation of Harry Fuecks article on phpPatterns, 12.02.2002

Model View Controller Pattern and PHP

2 - MVC Version 2

mardi 18 avril 2006, par Thierry Bothorel

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

Original article MVC Pattern (Version 2) only provide the new example code to download. I just add to the article the content of the two modified classes, View and Controller (Model and DataAccess classes are left unchanged) and some of the original comments.

This is an updated version of the Model View Controller pattern which attempts to adhere more stringently to the definition of that pattern.

The first version of this PHP pattern can be found here. Thanks to some useful comments, I’ve updated it now to be closer to the widely accepted definition of an MVC pattern. This article updates the code while leaving the earlier article to give an overview of the concepts.

As an interesting side note, ran into Phrame today : a port of the Jakarta Struts project to PHP, which provides an excellent means for achieving “looser” coupling between Model and View (loose coupling ?).

UML wise we’re now talking

GIF - 5.3 ko
MVC révisé

I’ll leave it otherwise for the code to explain itself, so we can move on to other things…

Ressources

Jason E. Sweat does a great job of explaining MVC in the May 2003 php


ProductController.php

<?php
/**
*  Controls the application
*/
class ProductController {
    var
$model;
    var
$view;

    
//! A constructor.
    /**
    * Constucts a new ProductController object
    * @param $model an instance of the ProductModel class
    * @param $getvars the incoming HTTP GET method variables
    */
    
function ProductController (& $dao) {
        
$this->model=& new ProductModel($dao);
    }
}

class
ProductItemController extends ProductController {
   
//! A constructor.
    /**
    * Constucts a new ProductItemController object
    * @param $model an instance of the ProductModel class
    * @param $getvars the incoming HTTP GET method variables
    */
    
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 {
   
//! A constructor.
    /**
    * Constucts a new ProductTableController object
    * @param $model an instance of the ProductModel class
    * @param $getvars the incoming HTTP GET method variables
    */
    
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
/**
*  Binds product data to HTML rendering
*/
class ProductView {
    
/**
    * Private
    * $model an instance of the ProductModel class
    */
    
var $model;

    
/**
    * Private
    * $output rendered HTML is stored here for display
    */
    
var $output;

    
//! A constructor.
    /**
    * Constucts a new ProductView object
    * @param $model an instance of the ProductModel class
    */
    
function ProductView (&$model) {
        
$this->model=& $model;
    }

    
//! A manipulator
    /**
    * Builds the top of an HTML page
    * @return void
    */
    
function header () {
        
$this->output=<<<EOD
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Our Products </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">Our Products</div>
EOD;
        
$this->output.="\n<div align=\"right\"><a href=\"".
            
$_SERVER['PHP_SELF']."\">Start Over</a></div>\n";

    }

    
//! A manipulator
    /**
    * Builds the bottom of an HTML page
    * @return void
    */
    
function footer () {
        
$this->output.="</body>\n</html>";
    }
}

class
ProductItemView extends ProductView {
    
/**
    * Private
    * $productID ID of product to render
    */
    
var $productID;

    
//! A constructor.
    /**
    * Constucts a new ProductView object
    * @param $model an instance of the ProductModel class
    */
    
function ProductItemView (&$model,$productID) {
        
ProductView::ProductView($model);
        
$this->productID=$productID;
    }

    
//! A manipulator
    /**
    * Renders a single product
    * @return void
    */
    
function productItem() {
        
$this->model->listProduct($this->productID);
        while (
$product=$this->model->getProduct() ) {
            
$this->output.="<p><b>Name</b>:".$product['PRODUCTNAME']."</p>".
                
"<p><b>Price</b>:".$product['UNITPRICE']."</p>".
                
"<p><b># In Stock</b>:".$product['UNITSINSTOCK']."</p>";
            if (
$product['DISCONTINUED']==1 ) {
                
$this->output.="<p>This product has been discontinued.</p>";
            }
        }
    }

    
//! An accessor
    /**
    * Returns the rendered HTML
    * @return string
    */
    
function toString () {
        
$this->header();
        
$this->productItem();
        
$this->footer();
        return
$this->output;
    }
}

class
ProductTableView extends ProductView {
    
/**
    * Private
    * $rowsperpage number of results per page
    */
    
var $rowsPerPage;
    
/**
    * Private
    * $rownum begin display of rows at this ID
    */
    
var $rowNum;

    
//! A constructor.
    /**
    * Constucts a new ProductView object
    * @param $model an instance of the ProductModel class
    */
    
function ProductTableView (&$model,$rowsPerPage=20,$rowNum=0) {
        
ProductView::ProductView($model);
        
$this->rowsPerPage=$rowsPerPage;
        
$this->rowNum=$rowNum;
    }

    
//! A manipulator
    /**
    * Renders a product table
    * @return void
    */
    
function productTable() {
        
$this->model->listProducts($this->rowNum,$this->rowsPerPage);
        
$this->output.="<table width=\"600\" align=\"center\">\n<tr>\n".
                
"<td class=\"heading\">Name</td>\n".
                
"<td class=\"heading\">Price</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> </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> </td>\n";            
        }
        
$this->output.="</tr>\n</table>\n";
    }

    
//! An accessor
    /**
    * Returns the rendered HTML
    * @return string
    */
    
function toString () {
        
$this->header();
        
$this->productTable();
        
$this->footer();
        return
$this->output;
    }
}
?>

and finally 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());

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


1 Message

Répondre à cet article