Saturday, March 15, 2014

PHP MVC step by step

A Brief History of Model-View-Controller

Let’s go all the way back to the 70s. Man has been to the moon, the civil rights movement has been a huge success, and the counterculture revolution is in full swing. More importantly for us, computer science has now established itself as a legitimate field, not just the eccentric hobby of people with huge glasses and bigger beards. Some of the brightest minds in engineering and mathematics are collaborating in research labs at Stanford, Berkeley and the dozens of private companies like Xerox and HP in what would later become Silicon Valley.
It’s against this backdrop that a bunch of very talented programmers have gathered at the Learning Research Group (LRG) of Xerox PARC in Palo Alto, California (the current home of Apple). These programmers are Alan Kay, Dan Ingalls, Adele Goldberg, Ted Kaehler, and Scott Wallace, among others. Together, they help create a programming language they call ‘Smalltalk’. It’s already been a few years since the development of the C language at Bell Labs; there are already some software design standards in place. However, the invention of the Smalltalk programming language would affect virtually all these standards, and set the tone for the future of programming.
It was from this language that the Model-View-Controller pattern first emerged. Ted Kaehler is usually given credit for its development in 1978 in a paper titled ‘A note on DynaBook requirements’, though his first name for it was ‘Thing-Model-View-Set’. The aim of this MVC pattern was to bring the user ‘closer’ to the digital model that existed inside the computer program. In Kaehler’s own words, the “user was czar”, and the MVC helped mediate the way the user could interact with a software program.
If that sounds too abstract to you, don’t worry – you’ll have a firm understanding of MVC by the time we’re done.
What you should know for now is that MVC described the way a user could interact with a computer program. This would later go on to inform Graphical User Interfaces (GUIs), and thus, by proxy, pretty much all of computer science. If it wasn’t for Kaehler and his MVC pattern, you might still be typing commands into a terminal right now.

So What Exactly is a Model-View-Controller?

A Model-View-Controller is a pattern of software architecture. It controls how different applications interact with a user.
Here’s a fun fact: you’re looking at a MVC right now.
This web page is a perfect example of the MVC structure. Here, the HTML structure of this web page is the model, the CSS stylesheets that control its appearance are the ‘View’, and the browser that you use to interact with the web page is the ‘controller’.
Let’s look at this in a little more detail:
Model: The model is a representation of knowledge. That is, the model contains the actual data that has to be shown to the user. All data is held in a structured format. For example, the HTML on this web page holds the actual text that you see inside structured HTML <tags>.
View: The view is a visual representation of the model. The view informs the way data structured in the model will be made visible to the user. For example, the HTML may hold the text, but the colors, font size and font style information is actually held by independent CSS stylesheets – i.e. the view.
Controller: A controller is the environment that bridges the divide between the user and the system. This is the device that lets the user interact with the system. In the above examples, the browser is the controller that helps you interact with the web page.
One way of representing this is as follows:
Here’s a crude analogy: the muscles, bones and organs in your body are the ‘model’ that holds everything vital. The skin, hair, etc. are the ‘view’ that controls the outward representation of the muscles and bones (the model). Your senses are the ‘controller’ that helps the ‘model’ interact with the world.
Want to make web applications? Learn dynamic web programming with PHP in this course.

MVC in PHP

As a programmer, you’ll most likely to encounter MVC in a Ruby on Rails or Django project. However, it is also used in some PHP web frameworks, though the implementation isn’t nearly always uniform or in strict accordance with the theoretical foundation of MVC as laid down by Ted Kaehler.
CakePHP, which is one of the most popular PHP frameworks, uses an interpretation of the Ruby on Rails MVC pattern. If you download a copy of the framework, you’ll see the following directory structure in /app/:
Here, the model, view and controller are included in separate folders. This is what /view/ contains:
/Model/:
And /Controller/:
Here’s the MVC in CodeIgniter, another very popular PHP framework:
You can learn more about using Codeigniter in this course.
However, CakePHP and CodeIgniter’s approach isn’t pure MVC, for here, the view and the model can interact with each other. In a pure MVC, all interactions must be handled by the controller alone. Most frameworks – CakePHP included – tend to treat the View as little more than a CSS template that controls the way the web page/app looks. The MVC approach is typically muddled in most PHP frameworks, both because of a poor translation of the Ruby on Rails and other similar frameworks. You don’t necessarily need to use MVC in your programs – WordPress isn’t MVC compliant – but it certainly will improve your application design.
MVC is an abstract, theoretical topic that can be difficult to grasp for beginners. You can learn more about it in this course on PHP programming from scratch.
Ref --> http://williamjxj.com/wordpress/?page_id=557

According to Wikipedia, Model – View – Controller (MVC) is an architectural pattern used in software engineering. Successful use of the pattern isolates business logic from user interface considerations, resulting in an application where it is easier to modify either the visual appearance of the application or the underlying business rules without affecting the other. In MVC, the model represents the information (the data) of the application; the view corresponds to elements of the user interface such as text, checkbox items, and so forth; and the controller manages the communication of data and the business rules used to manipulate the data to and from the model. In simpler words:
  1. Model handles all our database logic. Using the model we connect to our database and provide an abstraction layer.
  2. Controller represents all our business logic i.e. all $_REQUEST.
  3. View represents our presentation logic i.e HTML/Javascript code.
Lets dive right in
The Directory Structure
Directory Structure
Although we will not be a couple of directories mentioned above for this tutorial, we should have them in place for future expansion. Let me explain the purpose of each directory:
  • application – application specific code
  • config – database/server configuration
  • db – database backups
  • library – framework code
  • public – application specific js/css/images
  • scripts – command-line utilities
  • tmp – temporary data
Once we have our directory structure ready, let us understand a few coding conventions.
Coding Conventions
  • MySQL tables will always be lowercase and plural e.g. items, cars
  • Models will always be singular and first letter capital e.g. Item, Car
  • Controllers will always have “Controller” appended to them. e.g. ItemsController, CarsController
  • Views will have plural name followed by action name as the file. e.g. items/view.php, cars/buy.php
We first add .htaccess file in the root directory which will redirect all calls to the public folder
1.<IfModule mod_rewrite.c>
2.    RewriteEngine on
3.    RewriteRule    ^$    public/    [L]
4.    RewriteRule    (.*) public/$1    [L]
5. </IfModule>
We then add .htaccess file to our public folder which redirect all calls to index.php. Line 3 and 4 make sure that the path requested is not a filename or directory. Line 7 redirects all such paths to index.php?url=PATHNAME
  • 01.<IfModule mod_rewrite.c>
  • 02.RewriteEngine On
  • 03. 
  • 04.RewriteCond %{REQUEST_FILENAME} !-f
  • 05.RewriteCond %{REQUEST_FILENAME} !-d
  • 06. 
  • 07.RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
  • 08. 
  • 09.</IfModule>
This redirection has many advantages-
a) we can use it for bootstrapping i.e. all calls go via our index.php except for images/js/cs.
b) we can use pretty/seo-friendly URLS
c) we have a single entry point
Now we add index.php to our public folder
1.<?php   
2. 
3.define(‘DS’, DIRECTORY_SEPARATOR);
4.define(‘ROOT’, dirname(dirname(__FILE__)));
5. 
6.$url = $_GET['url'];
7. 
8.require_once (ROOT . DS . ‘library’ . DS . ‘bootstrap.php’);
Notice that I have purposely not included the closing ?>. This is to avoid injection of any extra whitespaces in our output. For more, I suggest you view Zend’s coding style.
Our index.php basically set the $url variable and calls bootstrap.php which resides in our library directory.
Now lets view our bootstrap.php
1.<?php
2. 
3.require_once (ROOT . DS . ‘config’ . DS . ‘config.php’);
4.require_once (ROOT . DS . ‘library’ . DS . ‘shared.php’);
Yes these requires could be included directly in index.php. But have not been on purpose to allow future expansion of code.
Now let us have a look at shared.php, finally something that does some real work
01.<?php
02. 
03./** Check if environment is development and display errors **/
04. 
05.function setReporting() {
06.if (DEVELOPMENT_ENVIRONMENT == true) {
07.    error_reporting(E_ALL);
08.    ini_set(‘display_errors’,'On’);
09.} else {
10.    error_reporting(E_ALL);
11.    ini_set(‘display_errors’,'Off’);
12.    ini_set(‘log_errors’, ‘On’);
13.    ini_set(‘error_log’, ROOT.DS.’tmp’.DS.’logs’.DS.’error.log’);
14.}
15.}
16. 
17./** Check for Magic Quotes and remove them **/
18. 
19.function stripSlashesDeep($value) {
20.    $value = is_array($value) ? array_map(‘stripSlashesDeep’, $value) : stripslashes($value);
21.    return $value;
22.}
23. 
24.function removeMagicQuotes() {
25.if ( get_magic_quotes_gpc() ) {
26.    $_GET    = stripSlashesDeep($_GET   );
27.    $_POST   = stripSlashesDeep($_POST  );
28.    $_COOKIE = stripSlashesDeep($_COOKIE);
29.}
30.}
31. 
32./** Check register globals and remove them **/
33. 
34.function unregisterGlobals() {
35.    if (ini_get(‘register_globals’)) {
36.  $array = array(‘_SESSION’, ‘_POST’, ‘_GET’, ‘_COOKIE’, ‘_REQUEST’, ‘_SERVER’, ‘_ENV’, ‘_FILES’);
37.  foreach ($array as $value) {
38.      foreach ($GLOBALS[$value] as $key => $var) {
39.    if ($var === $GLOBALS[$key]) {
40.  unset($GLOBALS[$key]);
41.    }
42.      }
43.  }
44.    }
45.}
46. 
47./** Main Call Function **/
48. 
49.function callHook() {
50.    global $url;
51. 
52.    $urlArray = array();
53.    $urlArray = explode(“/”,$url);
54. 
55.    $controller = $urlArray[0];
56.    array_shift($urlArray);
57.    $action = $urlArray[0];
58.    array_shift($urlArray);
59.    $queryString = $urlArray;
60. 
61.    $controllerName = $controller;
62.    $controller = ucwords($controller);
63.    $model = rtrim($controller, ‘s’);
64.    $controller .= ‘Controller’;
65.    $dispatch = new $controller($model,$controllerName,$action);
66. 
67.    if ((int)method_exists($controller, $action)) {
68.  call_user_func_array(array($dispatch,$action),$queryString);
69.    } else {
70.  /* Error Generation Code Here */
71.    }
72.}
73. 
74./** Autoload any classes that are required **/
75. 
76.function __autoload($className) {
77.    if (file_exists(ROOT . DS . ‘library’ . DS . strtolower($className) . ‘.class.php’)) {
78.  require_once(ROOT . DS . ‘library’ . DS . strtolower($className) . ‘.class.php’);
79.    } else if (file_exists(ROOT . DS . ‘application’ . DS . ‘controllers’ . DS . strtolower($className) . ‘.php’)) {
80.  require_once(ROOT . DS . ‘application’ . DS . ‘controllers’ . DS . strtolower($className) . ‘.php’);
81.    } else if (file_exists(ROOT . DS . ‘application’ . DS . ‘models’ . DS . strtolower($className) . ‘.php’)) {
82.  require_once(ROOT . DS . ‘application’ . DS . ‘models’ . DS . strtolower($className) . ‘.php’);
83.    } else {
84.  /* Error Generation Code Here */
85.    }
86.}
87. 
88.setReporting();
89.removeMagicQuotes();
90.unregisterGlobals();
91.callHook();
Let me explain the above code briefly. The setReporting() function helps us display errors only when theDEVELOPMENT_ENVIRONMENT is true. The next move is to remove global variables and magic quotes. Another function that we make use of is __autoload which helps us load our classes automagically. Finally, we execute the callHook() function which does the main processing.
First let me explain how each of our URLs will look – yoursite.com/controllerName/actionName/queryString
So callHook() basically takes the URL which we have received from index.php and separates it out as $controller, $action and the remaining as $queryString. $model is the singular version of $controller.
e.g. if our URL is http://www.todo.com/items/view/1/first-item, then
Controller is items
Model is item (corresponding mysql table)
View is delete
Action is delete
Query String is an array (1,first-item)
After the separation is done, it creates a new object of the class $controller.”Controller” and calls the method $action of the class.
Now let us create a few classes first namely our base Controller class which will be used as the base class for all our controllers, our Model class which will be used as base class for all our models.
First the controller.class.php:
01.<?php
02.class Controller {
03. 
04.    protected $_model;
05.    protected $_controller;
06.    protected $_action;
07.    protected $_template;
08. 
09.    function __construct($model, $controller, $action) {
10. 
11.  $this->_controller = $controller;
12.  $this->_action = $action;
13.  $this->_model = $model;
14. 
15.  $this->$model =&amp; new $model;
16.  $this->_template =&amp; new Template($controller,$action);
17. 
18.    }
19. 
20.    function set($name,$value) {
21.  $this->_template->set($name,$value);
22.    }
23. 
24.    function __destruct() {
25.      $this->_template->render();
26.    }
27. 
28.}
The above class is used for all communication between the controller, the model and the view (template class). It creates an object for the model class and an object for template class. The object for model class has the same name as the model itself, so that we can call it something like $this->Item->selectAll(); from our controller.
While destroying the class we call the render() function which displays the view (template) file.
Now let us look at our model.class.php
01.<?php
02.class Model extends SQLQuery {
03.    protected $_model;
04. 
05.    function __construct() {
06. 
07.  $this->connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME);
08.  $this->_model = get_class($this);
09.  $this->_table = strtolower($this->_model).”s”;
10.    }
11. 
12.    function __destruct() {
13.    }
14.}
The Model class extends the SQLQuery class which basically is an abstraction layer for the mySQL connectivity. Depending on your requirements you can specify any other DB connection class that you may require.
Now let us have a look at the SQLQuery.class.php
01.<?php
02. 
03.class SQLQuery {
04.    protected $_dbHandle;
05.    protected $_result;
06. 
07.    /** Connects to database **/
08. 
09.    function connect($address, $account, $pwd, $name) {
10.  $this->_dbHandle = @mysql_connect($address, $account, $pwd);
11.  if ($this->_dbHandle != 0) {
12.      if (mysql_select_db($name, $this->_dbHandle)) {
13.    return 1;
14.      }
15.      else {
16.    return 0;
17.      }
18.  }
19.  else {
20.      return 0;
21.  }
22.    }
23. 
24.    /** Disconnects from database **/
25. 
26.    function disconnect() {
27.  if (@mysql_close($this->_dbHandle) != 0) {
28.      return 1;
29.  }  else {
30.      return 0;
31.  }
32.    }
33. 
34.    function selectAll() {
35.  $query = ‘select * from `’.$this->_table.’`';
36.  return $this->query($query);
37.    }
38. 
39.    function select($id) {
40.  $query = ‘select * from `’.$this->_table.’` where `id` = ”.mysql_real_escape_string($id).”’;
41.  return $this->query($query, 1);
42.    }
43. 
44.    /** Custom SQL Query **/
45. 
46.    function query($query, $singleResult = 0) {
47. 
48.  $this->_result = mysql_query($query, $this->_dbHandle);
49. 
50.  if (preg_match(“/select/i”,$query)) {
51.  $result = array();
52.  $table = array();
53.  $field = array();
54.  $tempResults = array();
55.  $numOfFields = mysql_num_fields($this->_result);
56.  for ($i = 0; $i < $numOfFields; ++$i) {
57.      array_push($table,mysql_field_table($this->_result, $i));
58.      array_push($field,mysql_field_name($this->_result, $i));
59.  }
60. 
61.      while ($row = mysql_fetch_row($this->_result)) {
62.    for ($i = 0;$i < $numOfFields; ++$i) {
63.  $table[$i] = trim(ucfirst($table[$i]),”s”);
64.  $tempResults[$table[$i]][$field[$i]] = $row[$i];
65.    }
66.    if ($singleResult == 1) {
67.  mysql_free_result($this->_result);
68.  return $tempResults;
69.    }
70.    array_push($result,$tempResults);
71.      }
72.      mysql_free_result($this->_result);
73.      return($result);
74.  }
75. 
76.    }
77. 
78.    /** Get number of rows **/
79.    function getNumRows() {
80.  return mysql_num_rows($this->_result);
81.    }
82. 
83.    /** Free resources allocated by a query **/
84. 
85.    function freeResult() {
86.  mysql_free_result($this->_result);
87.    }
88. 
89.    /** Get error string **/
90. 
91.    function getError() {
92.  return mysql_error($this->_dbHandle);
93.    }
94.}
The SQLQuery.class.php is the heart of our framework. Why? Simply because it can really help us reduce our work while programming by creating an SQL abstraction layer. We will dive into an advanced version of SQLQuery.class.php in the next tutorial. For now lets just keep it simple.
The connect() and disconnect() functions are fairly standard so I will not get into too much detail. Let me specifically talk about the query class. Line 48 first executes the query. Let me consider an example. Suppose our SQL Query is something like:
SELECT table1.field1 , table1.field2, table2.field3, table2.field4 FROM table1,table2 WHERE ….
Now what our script does is first find out all the output fields and their corresponding tables and place them in arrays – $field and $table at the same index value. For our above example, $table and $field will look like
$field = array(field1,field2,field3,field4);
$table = array(table1,table1,table2,table2);
The script then fetches all the rows, and converts the table to a Model name (i.e. removes the plural and capitalizes the first letter) and places it in our multi-dimensional array and returns the result. The result is of the form $var['modelName']['fieldName']. This style of output makes it easy for us to include db elements in our views.
Now let us have a look at template.class.php
01.<?php
02.class Template {
03. 
04.    protected $variables = array();
05.    protected $_controller;
06.    protected $_action;
07. 
08.    function __construct($controller,$action) {
09.  $this->_controller = $controller;
10.  $this->_action = $action;
11.    }
12. 
13.    /** Set Variables **/
14. 
15.    function set($name,$value) {
16.  $this->variables[$name] = $value;
17.    }
18. 
19.    /** Display Template **/
20. 
21.    function render() {
22.  extract($this->variables);
23. 
24.      if (file_exists(ROOT . DS . ‘application’ . DS . ‘views’ . DS . $this->_controller . DS . ‘header.php’)) {
25.    include (ROOT . DS . ‘application’ . DS . ‘views’ . DS . $this->_controller . DS . ‘header.php’);
26.      } else {
27.    include (ROOT . DS . ‘application’ . DS . ‘views’ . DS . ‘header.php’);
28.      }
29. 
30.  include (ROOT . DS . ‘application’ . DS . ‘views’ . DS . $this->_controller . DS . $this->_action . ‘.php’);      
31. 
32.      if (file_exists(ROOT . DS . ‘application’ . DS . ‘views’ . DS . $this->_controller . DS . ‘footer.php’)) {
33.    include (ROOT . DS . ‘application’ . DS . ‘views’ . DS . $this->_controller . DS . ‘footer.php’);
34.      } else {
35.    include (ROOT . DS . ‘application’ . DS . ‘views’ . DS . ‘footer.php’);
36.      }
37.    }
38. 
39.}
The above code is pretty straight forward. Just one point- if it does not find header and footer in theview/controllerName folder then it goes for the global header and footer in the view folder.
Now all we have to add is a config.php in the config folder and we can begin creating our first model, view and controller!
01.<?php
02. 
03./** Configuration Variables **/
04. 
05.define (‘DEVELOPMENT_ENVIRONMENT’,true);
06. 
07.define(‘DB_NAME’, ‘yourdatabasename’);
08.define(‘DB_USER’, ‘yourusername’);
09.define(‘DB_PASSWORD’, ‘yourpassword’);
10.define(‘DB_HOST’, ‘localhost’);
Phew! Now let us create our first mini-todo application. We first create a database “todo” and execute the following SQL queries
1.CREATE TABLE `items` (
2.  `id` int(11) NOT NULL auto_increment,
3.  `item_name` varchar(255) NOT NULL,
4.  PRIMARY KEY  (`id`)
5.);
6. 
7.INSERT INTO `items` VALUES(1, ‘Get Milk’);
8.INSERT INTO `items` VALUES(2, ‘Buy Application’);
Once that is done, we add item.php to our model folder with the following contents
1.<?php
2. 
3.class Item extends Model {
4. 
5.}
Write it is empty, but will have more information when we expand our framework in Part 2.
Now create a file called itemscontroller.php in the controller folder
01.<?php
02. 
03.class ItemsController extends Controller {
04. 
05.    function view($id = null,$name = null) {
06. 
07.  $this->set(‘title’,$name.’ – My Todo List App’);
08.  $this->set(‘todo’,$this->Item->select($id));
09. 
10.    }
11. 
12.    function viewall() {
13. 
14.  $this->set(‘title’,'All Items – My Todo List App’);
15.  $this->set(‘todo’,$this->Item->selectAll());
16.    }
17. 
18.    function add() {
19.  $todo = $_POST['todo'];
20.  $this->set(‘title’,'Success – My Todo List App’);
21.  $this->set(‘todo’,$this->Item->query(‘insert into items (item_name) values (”.mysql_real_escape_string($todo).”)’));
22.    }
23. 
24.    function delete($id = null) {
25.  $this->set(‘title’,'Success – My Todo List App’);
26.  $this->set(‘todo’,$this->Item->query(‘delete from items where id = ”.mysql_real_escape_string($id).”’));
27.    }
28. 
29.}
Finally create a folder called items in the views folder and create the following files in it-
view.php
1.<h2><?php echo $todo['Item']['item_name']?></h2>
2. 
3.    <a class=”big” href=”../../../items/delete/<?php echo $todo['Item']['id']?>”>
4.    <span class=”item”>
5.    Delete this item
6.    </span>
7.    </a>
viewall.php
01.<form action=”../items/add” method=”post”>
02.<input type=”text” value=”I have to…” onclick=”this.value=”” name=”todo”> <input type=”submit” value=”add”>
03.</form>
04.<br/><br/>
05.<?php $number = 0?>
06. 
07.<?php foreach ($todo as $todoitem):?>
08.    <a class=”big” href=”../items/view/<?php echo $todoitem['Item']['id']?>/<?php echo strtolower(str_replace(” “,”-”,$todoitem['Item']['item_name']))?>”>
09.    <span class=”item”>
10.    <?php echo ++$number?>
11.    <?php echo $todoitem['Item']['item_name']?>
12.    </span>
13.    </a><br/>
14.<?php endforeach?>
delete.php
1.<a class=”big” href=”../../items/viewall”>Todo successfully deleted. Click here to go back.</a>
add.php
1.<a class=”big” href=”../items/viewall”>Todo successfully added. Click here to go back.</a>
header.php
01.<html>
02.<head>
03.<title><?php echo $title?></title>
04.<style>
05..item {
06.width:400px;
07. 
08.}
09. 
10.input {
11.    color:#222222;
12.font-family:georgia,times;
13.font-size:24px;
14.font-weight:normal;
15.line-height:1.2em;
16.    color:black;
17.}
18. 
19. a {
20.    color:#222222;
21.font-family:georgia,times;
22.font-size:24px;
23.font-weight:normal;
24.line-height:1.2em;
25.    color:black;
26.    text-decoration:none;
27. 
28.}
29. 
30.a:hover {
31.    background-color:#BCFC3D;
32.}
33.h1 {
34.color:#000000;
35.font-size:41px;
36.letter-spacing:-2px;
37.line-height:1em;
38.font-family:helvetica,arial,sans-serif;
39.border-bottom:1px dotted #cccccc;
40.}
41. 
42.h2 {
43.color:#000000;
44.font-size:34px;
45.letter-spacing:-2px;
46.line-height:1em;
47.font-family:helvetica,arial,sans-serif;
48. 
49.}
50.</style>
51.</head>
52.<body>
53.<h1>My Todo-List App</h1>
footer.php
1.</body>
2.</html>
Now assuming you have uploaded the directory structure to the todo folder, point your browser to:
http://localhost/todo/items/viewall
Todo List App
Where do we go from here?
Firstly we have achieved a lot by completing this tutorial – we have been able to separate our presentation logic from our business logic and database logic. We have also been able to provide for pretty-urls and extensibility..
The above is part 1, the source can be download here. The following is the new version which we have implemented a simple e-commerce website consisting of categories, subcategories, products and tags (for products). The example will help you understand the various relationships between the tables and most of the new functionality provided by this part of the framework.
What’s New
config/inflection.php
The inflection configuration file enables us to use irregular words i.e. words which do not have a standard plural name. This file is used in conjunction with library/inflection.class.php
config/routing.php
The routing configuration file enables us to specify default controller and action. We can also specify custom redirects using regular expressions. Currently I have specified only one redirect i.e. http://localhost/framework/admin/categories/view will become http://localhost/framework/admin/categories_view where admin is the controller and categories_view is the action. This will enable us to create an administration centre with pretty URLs. You can specify others as per your requirements.
library/cache.class.php
The cache class is in its infancy. Currently there are two simple functions- set and get. The data is stored in a flat text-file in the cache directory. Currently only the describe function of the SQLQuery class uses this cache function.
library/html.class.php
The HTML class is used to aid the template class. It allows you to use a few standard functions for creating links, adding javascript and css. I have also added a function to convert links to tinyurls. This class can be used only in the views e.g. $html->includeJs(’generic.js’);
library/inflection.class.php
In the previous part, plural of words were created by adding only “s” to the word. However, for a more full-fledged version, we now use the inflection class with slight modifications. If you have a look at the class, it makes use of simple regular expressions. It would be nice to add a cache function to this class in future.
library/template.class.php
I have added a new variable called doNotRenderHeader which will enable you to not output headers for a particular action. This can be used in AJAX calls when you do not want to return the headers. It has to be called by the controller e.g. $this->doNotRenderHeader = 1;
library/vanillacontroller.class.php & vanillamodel.class.php
Pretty much unchanged, but I have added a prefix vanilla to them to emphasize on its simplicity library/sqlquery.class.php
The SQLQuery class is the heart of this framework. This class will enable you to use your tables as objects.
Let us understand the easy functions first – save() and delete()
The save() function must be used from the controller. The save() function can have two options- if an id is set, then it will update the entry; if it is not set, then it will create a new entry. For example let us consider the categories class i.e. application/controllers/categoriescontroller.php. We can have a function like the one below.
1.function new() {
2.   $this->Category->id = $_POST['id'];
3.   $this->Category->name = $_POST['name'];
4.   $this->Category->save();
5.}
If $this->Category->id = null; then it will create a new record in the categories table.
The delete() function enables you to delete a record from the table. A sample code could be as below. Although you should use POST instead of GET queries for deleting records. As a rule idempotent operations should use GET. Idempotent operations are those which do not change the state of the database (i.e. do not update/delete/insert rows or modify the database in anyway)
1.function delete($categoryId) {
2.   $this->Category->id = $categoryId;
3.   $this->Category->delete();
4.}
Now let us look at the search() function. I know it is a bit intimidating at first. But it is pretty straight forward after we break it down. During database design, we use the following convention:
1:1 Relationship
For a one is to one relationship, suppose we have two tables students and mentors and each student hasOne mentor, then in the students table we will have a field called ‘mentor_id’ which will store the id of the mentor from the mentors table.
1:Many Relationship
For a one is to many relationship, suppose we have two tables parents and children and each parent hasMany children, then in the children table we will have a field called ‘parent_id’ which will store the id of the parent from the parents table.
Many:Many Relationship
For a many is to many relationship, suppose we have two tables students and teachers and each student hasManyAndBelongsToMany teachers, then we create a new table called students_teachers with three fields: id, student_id and teacher_id. The naming convention for this table is alphabetical. i.e. if our tables are cars and animals, then the table should be named animals_cars and not cars_animals.
Now once we have created our database as per these conventions, we must tell our framework about their existence. Let us have a look at models/product.php.
1.class Product extends VanillaModel {
2.    var $hasOne = array(‘Category’ => ‘Category’);
3.    var $hasManyAndBelongsToMany = array(‘Tag’ => ‘Tag’);
4.}
The first Category is the alias and the second Category is the actual model. In most cases both will be the same. Let us consider the models/category.php where they are not.
1.<?php
2. 
3.class Category extends VanillaModel {
4.  var $hasMany = array(‘Product’ => ‘Product’);
5.  var $hasOne = array(‘Parent’ => ‘Category’);
6. 
7.}
Here each category has a parent category, thus our alias is Parent while model is Category. Thus we will have a field called parent_id in the categories table. To clearly understand these relationships, I suggest you create a couple of tables and test them out for yourself. In order to see the output, use code similar to the following in your controller.
1.function view() {
2.   $this->Category->id = 1;
3.   $this->Category->showHasOne();
4.   $this->Category->showHasMany();
5.   $this->Category->showHMABTM();
6.   $data = $this->Category->search();
7.   print_r($data);
8.}
Now let us try and understand the search() function. If there are no relationships, then the function simply does a select * from tableName (tableName is same as controllerName). We can influence this statement, by using the following commands:
where(’fieldName’,’value’) => Appends WHERE ‘fieldName’ = ‘value’
like(’fieldName’,’value’) => Appends WHERE ‘fieldName’ LIKE ‘%value%’
setPage(’pageNumber’) => Enables pagination and display only results for the set page number
setLimit(’fieldName’,’value’) => Allows you to modify the number of results per page if pageNumber is set. Its default value is the one set in config.php.
orderBy(’fieldName’,’Order’) => Appends ORDER BY ‘fieldName’ ASC/DESC
id = X => Will display only a single result of the row matching the id
Now let us consider when showHasOne() function has be called, then for each hasOne relationship, a LEFT JOIN is done (see line 91-99).
Now if showHasMany() function has been called, then for each result returned by the above query and for each hasMany relationship, it will find all those records in the second table which match the current result’s id (see line 150). Then it will push all those results in the same array. For example, if teachers hasMany students, then $this->Teacher->showHasMany() will search for teacher_id in the students table.
Finally if showHMABTM() function has been called, then for each result returned by the first query and for each hasManyAndBelongsToMany relationship, it will find all those records which match the current result’s id (see line 200-201). For example, if teachers hasManyAndBelongsToMany students, then $this->Teacher->showHMABTM() will search for teacher_id in students_teachers table.
On line 236, if id is set, then it will return a single result (and not an array), else it will return an array. The function then calls the clear() function which resets all the variables (line 368-380).
Now let us consider an example to enable pagination on products. The code in the controllers/productscontroller.php should look something similar to the following.
01.function page ($pageNumber = 1) {
02.  $this->Product->setPage($pageNumber);
03.  $this->Product->setLimit(’10′);
04.  $products = $this->Product->search();
05.  $totalPages = $this->Product->totalPages();
06.  $this->set(‘totalPages’,$totalPages);
07.  $this->set(‘products’,$products);
08.  $this->set(‘currentPageNumber’,$pageNumber);
09.}
Now our corresponding view i.e. views/products/page.php will be something like below.
01.<?php foreach ($products as $product):?>
02.<div>
03.<?php echo $product['Product']['name']?>
04.</div>
05.<?php endforeach?>
06. 
07.<?php for ($i = 1; $i <= $totalPages; $i++):?>
08.<div>
09.<?php if ($i == $currentPageNumber):?>
10.<?php echo $currentPageNumber?>
11.<?php else: ?>
12.<?php echo $html->link($i,’products/page/’.$i)?>
13.<?php endif?>
14.</div>
15.<?php endfor?>
Thus with a few lines of code we have enabled pagination on our products page with pretty URLs!
(/products/page/1, products/page/2 …)
If you look at the totalPages() function on line 384-397, you will see that it takes the existing query and strips of the LIMIT condition and returns the count. This count/limit gives us the totalPages.
Now suppose that we are in the categories controller and we want to implement a query on the products table. One way to implement this is using a custom query i.e. $this->Category->custom(‘select * from products where …’);
Alternatively, we can use the performAction function (line 49-57 in shared.php) to call an action of another controller. An example call in categoriescontroller.php would be something like below.
1.function view($categoryId = null, $categoryName = null) {
2.  $categories = performAction(‘products’,'findProducts’,array($categoryId,$categoryName));
3.}
And the corresponding code in productscontroller.php should be as below.
1.function findProducts ($categoryId = null, $categoryName = null) {
2.  $this->Product->where(‘category_id’,$categoryId);
3.  $this->Product->orderBy(‘name’);
4.  return $this->Product->search();
5.}
The above more or less sums up all the functionality of the SQLQuery class. You can easily extend this as per your requirements e.g. to cache results, add conditions to hasMany, hasOne, hasMABTM queries also etc.
I have also laid the foundation for implementing user registration functionality by specifying a beforeAction and afterAction function which will be executed for each controller action. This will enable us to call a function which checks whether the user cookie is set and is a valid user.
One more feature that I have implemented is to have an administration centre. For this purpose we create a dummy model called models/admin.php and set a variable called $abstract = true. This will tell our VanillaModel to not look for a corresponding table in the database. As stated before I have created a routing for admin/X/Y as admin/X_Y. Thus we can have URLs like admin/categories/delete/15 which will actually call the categories_delete(15) function in the controllers/admincontroller.php file.


EMail ITClassSL@gmail.com
Phon +94 777 337279

Wednesday, February 26, 2014

MySQL Database and Java Desktop GUI Application Development

Contents:

  1. Machine specification used for this task

  2. Pre-requirement

  3. Creating a Database

  4. Making a Connection to a Database

  5. Creating a Table

  6. Inserting a Sample Data

  7. Creating a New Java Desktop Project

  8. Running the Project for the First Time

  9. Customizing the GUI

  10. Re-run the Project and Testing Its Functionality

In this series of three parts, we will learn how to build Java desktop GUI application that connected to MySQL database. This tutorial is quite long containing a lot of screen snapshots to make it as details as possible. The original tutorial can be found at netbeans.org. All credits must go to the original authors.
Machine specification used for this task
  • Intel Pentium Core 2 Duo, 2.2 GHz,
  • Windows XP Pro SP2 + periodical patches + periodical updates.
  • 2 GB DDR2 RAM
  • 160 GB SATA HDD
  • 17” SyncMaster 713N monitor.
Pre-requirement: NetBeans 6.x.x and MySQL 5.x.x

Creating a Database


Firstly let create a database using MySQL Command Line Client console. We cannot find how to create a MySQL database using NetBeans. However there are wizard to create Java database for Derby database. After finishing the database creation, exit and open NetBeans.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


SQL statement to create database is:


CREATE DATABASE tid5013studentrecord;


Change the database name accordingly if you want.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


When the NetBeans IDE launched, go to the Services pane, expand the Databases folder and expand the Drivers sub-folder.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Making a Connection to a Database


Well, NetBeans 6.0 provides drivers for JDBC-ODBC (Windows driver for Microsoft Access/MSSQL), MySQL, Java and PostgreSQL database. This means that no need for us to install third party driver for these databases as version 5.5. Thanks to NetBEans and in the future there will be more drivers for other dominant databases used in the market such as Oracle, Sybase etc. A new driver can be added to NetBeans using the following steps.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


And fill in the needed information in the following Figure. Get the third party JDBC driver for various databases at sun.com.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Next, select MySQL (Connector/J driver) and right-click mouse button. Select Connect Using… context menu.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


The New Database Connection wizard launched. Use the following connection string. Key in the MySQL username as root and its password that you use to access your MySQL database.


jdbc:mysql://localhost:3306/tid5013studentrecord


The format for the connection string for this driver is:


jdbc:mysql://<hostname>:<database_access_port_number>/<database_name>


Change the database name accordingly if needed. Click the OK button.


Using root user is not a good practice. We need to create MySQL users and assign appropriate level of permissions and rights to those users and use them in different level of database accesses such as users for update, backup and many more. Left the root as the highest administrator similar to Windows (Administrator) and Linux (root) system access. Click the Remember password tick box if you want the password to be remembered so next time no need to key-in the password any more. Click OK.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


If your connection is successful it will be notified (Connection established) in the following frame and same as if it is fail. Click the OK button.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Now we are connected to the MySQL database through NetBeans. You can see icon for the established connection as shown below.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Creating a Table


Next step is to create table and then populate it with sample data. The following table describes our sample table structure. (The red record has some issue to be resolved later. There are some incompatibilities between java.util.date and java.sql.date here. Quick solution is to use int or String type for the stud_date_of_birth or we can separate the year, month and day into different fields/columns).


The structure for a studentrecord table
Column name
Data type
Constraints
student_id
VARCHAR(7)
NOT NULL PRIMARY KEY
stud_first_name
VARCHAR(15)
NOT NULL
stud_last_name
VARCHAR(15)
NOT NULL
stud_date_of_birth
DATE
NOT NULL
stud_address
VARCHAR(50)
NOT NULL
stud_program
VARCHAR(20)
NOT NULL
stud_marital_status
INT(2)
NOT NULL
stud_country
VARCHAR(20)
NOT NULL


And the following is the SQL script for our table creation.


CREATE TABLE IF NOT EXISTS studentrecord (

student_id VARCHAR(7),

stud_first_name VARCHAR(15) NOT NULL,

stud_last_name VARCHAR(15) NOT NULL,

stud_date_of_birth DATE NOT NULL,

stud_address VARCHAR(50) NOT NULL,

stud_program VARCHAR(20) NOT NULL,

stud_marital_status INT(2) NOT NULL,

stud_country VARCHAR(20) NOT NULL,

PRIMARY KEY (student_id)

) ENGINE=innodb;


To execute this SQL script, select the previously established connection (our MySQL database), right-click mouse and select Execute Command… context menu.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Type or copy-paste the SQL script into the SQL Command editor as shown below. Make sure you have chosen a proper database as blue highlighted in the Connection: field


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Then, run/execute the script by clicking the run/execute icon.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Verify the studentrecord database creation by using the following command in new SQL Command editor. You can also combine and execute/run this code together with the previous SQL script.


DESC studentrecord;


The following figure shows that our table has been successfully created. Congrats!!!

Next step is to populate the studentrecord with sample data.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Inserting a Sample Data


Use the following sample SQL scrip to insert sample data into out table. You can try creating your own sample data. Launch and use new SQL Command editor or you can overwrite the previous SQL script. Execute/run the script as done previously.

INSERT INTO studentrecord VALUES(
'88889','Albukori','Zaman Khan','1969-07-08',
'4-5, Dead Wood Street 5, 12000 Sintok, Kedah','MSc. IT',
'1','Malaysia');
INSERT INTO studentrecord VALUES(
'87990','Haslina','Mahathir','1970-11-12',
'345, New Smart Village, 17100 Nilai, N. Sembilan','MSc. ICT',
'2','Malaysia');
INSERT INTO studentrecord VALUES(
'79678','Mohammed','Fajr','1975-04-20',
'Pearl Apt, Level 10, Al-Hijr, 45200 Abu Dhabi','MSc. Expert System',
'2','UEA');
INSERT INTO studentrecord VALUES(
'88799','Mustar','Mohd Dali','1979-06-24',
'345, Side Village, Kerian, 12300 Jawa Barat','MSc. MultiMedia',
'1','Indonesia');
INSERT INTO studentrecord VALUES(
'78998','Satkorn','Chengmo','1968-01-26',
'34 Uptown Street #4, Tech Park, 78100 Bangkok','MSc. IT',
'2','Thailand');


Any success or fail will be notified in the Output window at the bottom of the NetBeans IDE. So don’t worry. A screen snapshot is shown below. Notice the different default colors used in the SQL script. Keywords, values and table name are in different colors and together with the report in the Output window, this makes our tasks in troubleshooting easier.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Verify our data/values insertion by using the following SQL statement.


SELECT * FROM studentrecord;


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


A complete MySQL script for this exercise is given below.

-- create a table
CREATE TABLE IF NOT EXISTS studentrecord (
student_id VARCHAR(7),
stud_first_name VARCHAR(15) NOT NULL,
stud_last_name VARCHAR(15) NOT NULL,
stud_date_of_birth DATE NOT NULL,
stud_address VARCHAR(50) NOT NULL,
stud_program VARCHAR(20) NOT NULL,
stud_marital_status INT(2) NOT NULL,
stud_country VARCHAR(20) NOT NULL,
PRIMARY KEY (student_id)
) ENGINE=innodb;
-- insert a sample data
INSERT INTO studentrecord VALUES(
'88889','Albukori','Zaman Khan','1969-07-08',
'4-5, Dead Wood Street 5, 12000 Sintok, Kedah','MSc. IT',
'1','Malaysia');
INSERT INTO studentrecord VALUES(
'87990','Haslina','Mahathir','1970-11-12',
'345, New Smart Village, 17100 Nilai, N. Sembilan','MSc. ICT',
'2','Malaysia');
INSERT INTO studentrecord VALUES(
'79678','Mohammed','Fajr','1975-04-20',
'Pearl Apt, Level 10, Al-Hijr, 45200 Abu Dhabi','MSc. Expert System',
'2','UEA');
INSERT INTO studentrecord VALUES(
'88799','Mustar','Mohd Dali','1979-06-24',
'345, Side Village, Kerian, 12300 Jawa Barat','MSc. MultiMedia',
'1','Indonesia');
INSERT INTO studentrecord VALUES(
'78998','Satkorn','Chengmo','1968-01-26',
'34 Uptown Street #4, Tech Park, 78100 Bangkok','MSc. IT',
'2','Thailand');

Next step is to create a GUI for our database access and manipulation. The following screen snapshots are self-explanatory.


Creating a New Java Desktop Project


Well, click File > select New Project.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Select Java in the Categories: and Java Desktop Application in the Projects: pane. Click Next.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Put the project name as StudentRecordApp and change the location if needed else just leave as it is. Select the Database Application in the Choose Application Shell pane. Click Next.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Select our previously created database connection in the Database Connection text field. We only have one table here, so no need to select any as shown in the Database Table: field. In this case we include all the table columns. You can exclude some columns if needed. Click Next button.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


By default the first radio button has been selected. Just leave as it is. Click Finish button and wait.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Here you are! Our database GUI template! This GUI can be built and run/executed as other Java project.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


You can view the GUI by clicking the Preview Design icon ().


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Running the Project for the First Time


Next let see our real GUI in action. You can build first and then run. In this case we directly run the project (in the process it will be built as other Java project). Select the StudentRecordApp project folder, right-click mouse and select Run menu.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Here is the Real GUI. Try the File menu and its sub-menu. In this case not all the record was displayed. Only the first three and this is our job to find the cause and it is a normal process in programming! Select any record and test the New (click New button and key-in new data and click Save to update new data), Delete (select a record to be deleted and press the Delete button) and Refresh (refresh the connection and update the data) buttons. All controls supposed to be working else we need to find the reasons and resolve it.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Customizing the GUI


Close this application. Let go back to the design page. Select the Stud Date Of Birth text field. Go to the Properties sheet and click the Binding.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Click the ellipses (…) at the end of the text field.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Try selecting the date int type in the Binding Expression: field, expand the studDateOfBirth java.util.Date and select date int and then click OK.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Re-run the Project and Testing Its Functionality


Re-run this project again.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Select any row of the table. All the record displayed but the Stud Date Of Birth just display the day only. However this program can be said 97% working.

If we want to add other component either to bind to the database table or not it is depend on our creativities now.










-----------------------------------------------------------------------------------------------------------------

Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Close the application and back to the design. Select, drag and drop the position of the table grid to the bottom of the frame as shown below.


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Re-run this project again and see the result!


Step-by-step on Java desktop GUI application development and MySQL screen snapshots


Regarding the Date Of Birth (DOB), well we think here is the reason. Searching in the Internet, the reason is the java.util.Date is not compatible with the java.sql.Date. Older java.util.Date package that contains date only already deprecated. The new version of this java.util.date contains date and time as well, while the java.sql.util only contains the date. Coding wise, we need to parse or convert to the java.sql.Date format. The validation and conversion features already available in the Java Server Faces (JSF) web development.


As said before we can fix this problem immediately. Easy solution is to use a String type for the stud_date_of_birth replacing the DATE data type. From this simple issue, that is why the database design stage is very important.


The structure for a studentrecord table
Column name
Data type
Constraints
student_id
VARCHAR(7)
NOT NULL PRIMARY KEY
stud_first_name
VARCHAR(15)
NOT NULL
stud_last_name
VARCHAR(15)
NOT NULL
stud_date_of_birth
VARCHAR(10)
NOT NULL
stud_address
VARCHAR(50)
NOT NULL
stud_program
VARCHAR(20)
NOT NULL
stud_marital_status
INT(2)
NOT NULL
stud_country
VARCHAR(20)
NOT NULL


Or we can separate the year, month and day into different fields/columns. (We have tried this, also failed).


stud_last_name
VARCHAR(15)
NOT NULL
stud_dob_day
INT(2)
NOT NULL
stud_dob_month
INT(2)
NOT NULL
stud_dob_year
INT(4)
NOT NULL
stud_address
VARCHAR(50)
NOT NULL


And for this case we need to create (I mean, NetBeans create for us and we re-arrange it in the frame) different fields for each column and we need to re-arrange the day, month and year in the standard format in the GUI such as:

Step-by-step on Java desktop GUI application development and MySQL screen snapshots

You can try both solution and let see the outputs however we will solve this issue in the next tutorial, replacing the DATA type to String and we will show the steps on how to edit a table while designing the GUI interface.
 
 
 


Individual / Group / Online classes in English / Sinhala / Tamil. Sample Projects/Assignments Exam Papers, Tutorials, Notes and Answers will be provided.

 

Call +94 777 33 7279 

eMail itclasssl@gmail.com 

Skype ITClassSL