PHP programming - MVC Architecture
Frank Yap

In this section you will learn details of an MVC architecture with an example of retail catalog site.
 
Resources

 
Lab Exercises

 
The following is a typical catalog of online retailer and this catalog is created by the code you would be studying. We will see the code for the page and analyze it to identify the MVC (Model, View, Controller) blocks.
 
Demo 1: Online catalog

 
    
 
 
View Module Running on Client side
 
Normally stored in Views folder.
This is HTML document layout file. It contains a refresh button and space allocation for product displays.
There is no PHP embedding in the code but this is a PHP file with an extension of php.
 
Exercise 1: HTML code in php file
 
Read the HTML code and identify elements. Understand when the function buttonGetProdList() gets called.
 
<!DOCTYPE html> 
<html lang="en"> 
<head><title>PHP Lab 13</title> 
</head> 
<body style="font-family:Verdana; color:#000; font-size:12pt;"> 
 
&nbsp;&nbsp;<button onClick="buttonGetProdList()">Refresh List</button> 
 
<br><br> 
<table id="idProdList" style="border-style:solid; width: 720px;"> 
</table> 
 
<!-- include Javascript code here --> 
 
<script type="text/javascript"> 
buttonGetProdList (); // auto fill of screen 
</script> 
 
</body> 
</html>
 

Javascript View Module Running on Client side   (Itself is MVC structure)
 
Normally stored in js (Javascript) folder as a *.js file.
This is Javascript code which fetches data from server using WebFunction and renders the product images and descriptions.
If HTML embedding is done by PHP this code would be run on the server side. If the list contains 100's of items it would load a lot of server CPU resource.
 
This code could be directly embedded in HTML code or could be a separate file and included in the HTML with a statement such as <script src="./js/yourFile.js" type="text/javascript"></script>.
 
Exercise 2: Javascript code on client side
 
 
Read the Javascript code and identify components. Understand the sequence of events when the function buttonGetProdList() gets called.
 
<script src="./js/jquery.js" type="text/javascript"> 
//<script src="jquery.js" type="text/javascript"> 
// ***** !!! This jQuery library should be inserted above jQuery code. 
// This "./" path string will work in MVC structure where the index.php  
// access gate file is always at the root of the subSite. 
// http://website.com/.../subSite/index.php?para=value... 
</script> 
 
<script type="text/javascript"> 
// ApacheDocRoot/.../subsite/index.php 
// ApacheDocRoot/pathToSubsiteRoot/index.php  
//var pathToSubsiteRoot = ".../phplab"; 
var pathToSubsiteRoot = "phplab"; // replace phplab with your "path to your SubSite root" if different 
var webFuncFile = "phpLab13_model.php"; // replace with your WebFunction handling file 
</script> 
 
 
<script type="text/javascript"> 
 
function buttonGetProdList (){ 
//alert ("func called"); 
var i = 0; 
var fileName = "/"+pathToSubsiteRoot+"/index.php?proc="+webFuncFile; // WebFunc processing file 
var actionFile = fileName; // send WebFunc data to this file 
// The action file sets _GET ['proc'] variable in server with value follows = sign. 
 
// WebFunction 
$.post ( // jQuery post method 
actionFile, 

cmnd:"getSpecialList", // function name 
folder:"specialsWeek121021" // argument 
}, 
function(data){ // returned data 
//alert (data); 
var xml = $($.parseXML (data)); 
var status = xml.find("STATUS").text(); 
if (status == "false"){ 
alert ("ERROR occurred"); 
} else { 
var imgBaseDir = xml.find("IMG_BASE").text(); 
var cols = 3; 
var col = 0; 
var strImg = ""; 
var strDesc = ""; 
var strTable = ""; 
 
xml.find("SPECIAL").each (function(){ // extract children's tag 
var imgLoc = $(this).find("IMAGE").text(); 
var desc = $(this).find("DESCRIPT").text(); 
var listPrice = $(this).find("LIST_PRICE").text(); 
var salePrice = $(this).find("SALE_PRICE").text(); 
 
if ((col % cols) == 0) { // start of row 
strImg = "<tr>"; 
strDesc = "<tr>"; 

var srcLoc = imgBaseDir + "/" + imgLoc; 
strImg += '<td><img src="' + srcLoc + '"></td>'; 
 
strDesc += "<td>"+desc+"<br>"; 
strDesc += '&nbsp;&nbsp;<font color="brown"><del>'+listPrice+"</del></font>&nbsp;&nbsp;"; 
strDesc += salePrice+"<br><br><br></td>"; 
 
col++; 
if ((col % cols) == 0) { // wrapped around, row is full  
strImg += "</tr>"; 
strDesc += "</tr>"; 
strTable += strImg + strDesc; 

});  
 
if ((col % cols) > 0) { // row is not full 
strImg += "</tr>"; 
strDesc += "</tr>"; 
strTable += strImg + strDesc; 

 
$("#idProdList").html(strTable); // jQuery DOM manipulation 


); 

</script>
 
Model Module Running on Server side
 
Normally stored in Models folder as a php file.
This is a model code interacting with Javascript. It fetches data for display updates. It reads data from storage folder and creates a string of porduct list.
 
Besides data reads from storage, all it does is concatenating strings.
Had the HTML embedding done by PHP, this code would also contain the display code shown in the Javascript code. It would add a lot more load to the server.
 
Exercise 3: PHP code on server side interacting with Javascript
 
Read the code and identify components. Understand how the argument is retrieved.
Understand what glob() function does.
Understand the difference between $fileDir and $baseDir.
Notice the only processing done with the fetched data is concatenation.
 
<?php 
if (isset($_POST ['cmnd'])) { 
$cmnd = $_POST ['cmnd']; 
 
// WebFunction 
if ($cmnd == "getSpecialList") { // function name 
$folder = $_POST ['folder']; // argument 
 
$dirName = dirname(__FILE__); // directory of file, c:\...subSite\x\y ile.php 
$dirName = dirname($dirName); // ../ 
$dirName = dirname($dirName); // ../ 
$fileDir = $dirName."/".$folder; // seen from server 
$str = "$fileDir/{*.xml,*.XML}"; 
 
$files = glob($str, GLOB_BRACE); 
if ($files === false) { 
$err = "ERROR: Specials file list. "; 
$resp = "<XMLDATA>"."<STATUS>false</STATUS>"."<ERROR>$err</ERROR>"."</XMLDATA>"; 
return; 

shuffle($files); 
 
$docRoot = $_SERVER['DOCUMENT_ROOT'] ; 
$pathToFolder = substr ($dirName, strlen($docRoot)); 
// http://website.com/pathToFolder/busiFolder 
 
if (($pathToFolder == "") || ($pathToFolder[0]=='/') || ($pathToFolder[0]=='\')) 
$baseDir = $pathToFolder."/".$folder; // seen from browser 
else 
$baseDir = "/".$pathToFolder."/".$folder; // seen from browser 
 
$xmlList = "<IMG_BASE>$baseDir</IMG_BASE>"; 
 
$begin = 0; 
$n = count($files); 
 
for ($i = $begin; $i < $n; $i++) { 
$status = false; 
$prodFile = $fileDir."/".basename($files[$i]); 
$data = ""; 
$fh = fopen ($prodFile, 'rb'); 
if ($fh != false) { 
$data = fread($fh, filesize($prodFile)); 
if ($data != false) { 
$status = true; 

fclose ($fh); 

 
if ($status == false) { 
$err = "ERROR: Specials file list. "; 
$resp = "<XMLDATA>"."<STATUS>false</STATUS>"."<ERROR>$err</ERROR>"."</XMLDATA>"; 
return; 
}  
 
$xmlList .= $data; // without Javascript this line should be expanded with all the display code 

 
$resp = "<XMLDATA>"."<STATUS>true</STATUS>"."<SPECIAL_LIST>".$xmlList."</SPECIAL_LIST></XMLDATA>"; 
echo $resp; // return data 
return; 


?>
 
Asset on Server side
 
Stored in daily business folder with an xml extension.
This is description of a product. It includes a link to an image file and descriptions of the item in XML data.
 
Notice that MySql is not used here for the storage of product data. Product data is stored in a folder as *.xml and *.jpg files. The client side would request data for products from a particular folder. This folder name would be passed as an argument in a WebFunction.
 
Exercise 4: XML data describing a product item
 
Read the code and understand how the XML is used to describe a product item.
 
<SPECIAL> 
<IMAGE>Toshiba Satellite S875 Notebook.jpg</IMAGE> 
<DESCRIPT> 
Toshiba Satellite S875 17.3" Core i7 8GB HD Notebook 
</DESCRIPT> 
<LIST_PRICE>999.99</LIST_PRICE> 
<SALE_PRICE>769.99</SALE_PRICE> 
</SPECIAL>
 
Block diagram of the MVC structure
 
The block diagram of the MVC structure looks like below.
 
Exercise 5: Block diagram of the MVC structure
Directory structure of the server MVC structure
 
The directory structure of our MVC model looks like this.
 
Exercise 6: Directory structure of MVC model
 
              (Website)
Internet ~~~ Apache Doc Root - SubSite Folder (project folder)
                                 |- index.php   // access gate
                                 |- protected
                                      |- controllers
                                      |- models
                                      |- views 
                                 |- js
                                 |- business Folders
 
The system can add more security by restricting direct access to files behind protected folder from external users using .htaccess configuration stored in the protected folder.
 
Controller Module Running on Server side
 
Normally stored in Controllers folder as a php file.
The code for controller looks like this.
Basically it filters the request and redirects the request to an appropriate handler.
 
Exercise 7: Controller code on server side
 
Read the code and identify components.
Understand how the protocol method is used to separate the processing block.
Understand how it processes based on folder structure.
 
<?php 
class MainController { 
 
public function proc() { 
$method = $_SERVER['REQUEST_METHOD'] ; 
 
if (strtoupper($method) == 'GET') { 
 
if (isset($_GET ['get'])) { 
$getTarget = $_GET ['get']; 
 
if ($getTarget == 'hello') { 
echo 'Hello User!'; 
return; 

 
$dirName = dirname(__FILE__); // directory of file, c:/...subSite/x/y/file.php 
$dirName = dirname($dirName); // ../ 
$file = $dirName."/"."views/$getTarget"; 
if (! file_exists($file)) 
return self::fileNotFound(); // or display default index file 
require $file; 
return; 
} else { 
$getFile = 'phpLab13_view.php'; // default index file 
 
$dirName = dirname(__FILE__); // directory of file, c:/...subSite/x/y/file.php 
$dirName = dirname($dirName); // ../ 
$file = $dirName."/"."views/$getFile"; 
if (! file_exists($file)) 
return self::fileNotFound(); // or display default index file 
require $file; 
return; 

return; 
}  
 
if (strtoupper($method) == 'POST') {  
 
if (isset($_GET ['proc'])) { // ajax action file's query part sets $_GET variable 
$procFile = $_GET ['proc']; 
 
$dirName = dirname(__FILE__); // directory of file, c:/...subSite/x/y/file.php 
$dirName = dirname($dirName); // ../ 
$file = $dirName."/"."models/$procFile"; 
if (! file_exists($file)){ 
return self::fileNotFound(); // or display default index file 

require $file; 
return; 

 
if (isset($_POST ['proc'])) { 
$procFile = $_POST ['proc']; 
 
$dirName = dirname(__FILE__); // directory of file, c:/...subSite/x/y/file.php 
$dirName = dirname($dirName); // ../ 
$file = $dirName."/"."models/$procFile"; 
if (! file_exists($file)) 
return self::fileNotFound(); // or display default index file 
require $file; 
return; 

}  

 
 
public function fileNotFound() { 
echo '<h2>The file you requested is not found.</h2><br>'; 
return; 


?>
 

Access Gate Running on Server side
 
All the access to the website that require PHP processing gets to and goes through the access gate index.php.
The access gate index.php file looks like below.
The code in the file immediately transfers execution to the controller but in a larger MVC framework it will transfer to an executive module for processing such as security checks before transfering to the controller.
 
Exercise 8: Access gate index.php code
 
Understand the directory dirname(__FILE__) is where index.php is stored.
Understand this directory is active current directory for all codes in all PHP files, because when a PHP file includes another file, the included file inherits the path environments.
 
<?php 
session_start(); // include here only 
 
$cont=dirname(__FILE__).'/protected/controllers/MainController.php'; 
 
require_once($cont); 
$controller = new MainController; 
$controller->proc(); 
?>
 
Homework Exercise

Create your own product list and display.
 
First create a product folder.
Add product images in the folder.
Add product description xml files in the folder.
 
Modify WebFunction argument to point to the new folder.
If you used the same tags in the xml files as in the example then the product list will be displayed without any other modifications in the code.
If you used different tags then you need to modify the Javascript code to correctly parse the XML data.
You will realize that either case there is no need to modify the PHP code.
 

Submit Javascript code and one xml file. Do not submit any other files.