-------------------------------------------------------------------------------------
To code our own MVC framework from scratch

Introduction

MVC architectural pattern is almost in everywhere today, whether you are working on Java, C#, PHP, iOS projects. This might not be 100% exact, but PHP community has the most amount of MVC frameworks. Today you might be using Zend, tomorrow on another project you might have to change to Yii or Laravel or CakePHP. If you are new to MVC frameworks and you just download one from the official website, you might feel overwhelmed when you look at the framework’s source code, yes, it is complex, as these popular frameworks are not written in a month - they are published, refined, tested again and again, and the functionalities are added constantly. So from my experience, knowing the core design methodologies of MVC  framework is critical, otherwise you might feel that you will have to learn another framework and another framework again and again when you get new projects using new frameworks.

The best way to understand MVC is to write you own MVC framework from scratch! In this series of articles I am going to show you how to code one, so that you might get to understand why certains things happen that way in a framework.

MVC architectural pattern

M: Model

V: View

C: Controller

The core concept of MVC is to separate business logic from displaying(the View part). First let me explain the whole workflow of an HTTP request & HTTP response. For example, we have a commerce website and we want to add a certain product. A very simple URL would be look like this:

http://bestshop.com/index.php?p=admin&c=goods&a=add

http://bestshop.com is the domain name or base URL;

p=admin means the Platform is admin panel, or the Backend site of the system. We also have a Frontend site, which is public to the world(in this case, it would be p=public)

c=goods&a=add means this URL requests the ‘goods’ Controller’s add action method.

Front Controller Design Pattern

What is index.php in the above example? This file is called ‘Front Controller’ in PHP’s MVC frameworks. The name is usually index.php, but you can name it something else(few people do that thought…) One of the function of this index.php file is, it works as the single entry point for any HTTP requests, that is, no matter what resource you request in the URL, it will all go into this index.php file first. But why? How does the magic happen? Front Controller design pattern is implemented in PHP using Apache HTTP server’s distribution configuration file called .htaccess. In this file, we can tell the Apache HTTP server to redirect all requests to index.php using its rewrite module. You can code similar to this:

Hide   Copy Code
  1. <IfModule mod_rewrite.c>
  2.  
  3. Options +FollowSymLinks
  4.  
  5. RewriteEngine on
  6.  
  7. # Send request via index.php
  8.  
  9. RewriteCond %{REQUEST_FILENAME} !-f
  10.  
  11. RewriteCond %{REQUEST_FILENAME} !-d
  12.  
  13. RewriteRule ^(.*)$ index.php/$1 [L]
  14.  
  15. </IfModule>

This configuration file is very powerful and when you change it, you don’t need to restart Apache. If you change Apache’s other configuration files, you need to restart it, the reason is that for other Apache configuration files, Apache only will read them when it’s started, that’s why any change requires a restart(Apache is mainly written in C by the way). But for .htaccess distribution configuration file, no restart is needed for any change.

Simply put, index.php will also do the proper initialization for the framework and it will route the request to the proper Controller(goodsController in above example) and an action method(member function) within that Controller class.

Our MVC Framework’s Structure

So let’s create our frameworks structure.

application directory is the web app’s directory;

framework directory is for the framework itself;

public directory is to store all the public static resources like html, css and js files.

index.php is the ‘entry-point’ file, the front controller.

Now within application folder, we create these subfolders:

config - stores the app’s configuration files

controllers - this is for all app’s Controller classes

model - this is for all app’s Model classes

view - this is for all app’s View classes

Now within the application/controllers folder, we will create two folders for the frontend and backend platforms:

And in the view folder, the same for frontend and backend:

As you can see, within the application folder, we created frontend and backend subfolder in controllers and views folder, as our application has a frontend site and a backend site. But why we did not do the same in the models folder?

Well, the reason here is, normally for a web app:

Frontend and Backend can be two different ‘websites’, but the are CRUD the same database, that’s why an internal user updated a product’s price, the price is immediately show on the frontend public page - backend and frontend share the same database/tables.

So that’s why both backend and frontend can share a set of Model classes, and that’s why we didn’t create separate folders in the models folder.

Now let’s move on to the framework directory, some frameworks name this folder using the framework’s name, say ‘symfony’. In this folder, we quickly create these subfolders first:

core - it will store the framework’s core classes

database - database related classes, such as database driver classes

helpers - help/assistant functions

libraries - for class libraries

Now move on to the public folder, we create these subfolders:

css - for css files

images - for images files

js - for javascript files

uploads - for uploaded files, such as uploaded images

Ok, so far this is our mini MVC framework’s structure.

Framework’s core class

Now under framework/core folder, we’ll create the framework’s first class - Framework.class.php in framework/core folder

Hide   Copy Code
  1. // framework/core/Framework.class.php
  2.  
  3. class Framework {
  4.  
  5. public static function run() {
  6.  
  7. echo "run()";
  8.  
  9. }

we created a static function called run(). Now test it in index.php:

Hide   Copy Code
  1. <?php
  2.  
  3. require "framework/core/Framework.class.php";
  4.  
  5. Framework::run();

You can see the result in browser(how to config your virtual host is skipped here). Normally this static function is called run() or bootstrap(). Within this function, we can do 3 main things here, as shown in the code below:

Hide   Shrink    Copy Code
  1. class Framework {
  2.  
  3. public static function run() {
  4.  
  5. // echo "run()";
  6.  
  7. self::init();
  8.  
  9. self::autoload();
  10.  
  11. self::dispatch();
  12.  
  13. }
  14.  
  15. private static function init() {
  16.  
  17. }
  18.  
  19. private static function autoload() {
  20.  
  21. }
  22.  
  23. private static function dispatch() {
  24.  
  25. }
  26.  
  27. }

Initialization

Here is the code for the init() method:

Hide   Shrink    Copy Code
  1. // Initialization
  2.  
  3. private static function init() {
  4.  
  5. // Define path constants
  6.  
  7. define("DS", DIRECTORY_SEPARATOR);
  8.  
  9. define("ROOT", getcwd() . DS);
  10.  
  11. define("APP_PATH", ROOT . 'application' . DS);
  12.  
  13. define("FRAMEWORK_PATH", ROOT . "framework" . DS);
  14.  
  15. define("PUBLIC_PATH", ROOT . "public" . DS);
  16.  
  17. define("CONFIG_PATH", APP_PATH . "config" . DS);
  18.  
  19. define("CONTROLLER_PATH", APP_PATH . "controllers" . DS);
  20.  
  21. define("MODEL_PATH", APP_PATH . "models" . DS);
  22.  
  23. define("VIEW_PATH", APP_PATH . "views" . DS);
  24.  
  25. define("CORE_PATH", FRAMEWORK_PATH . "core" . DS);
  26.  
  27. define('DB_PATH', FRAMEWORK_PATH . "database" . DS);
  28.  
  29. define("LIB_PATH", FRAMEWORK_PATH . "libraries" . DS);
  30.  
  31. define("HELPER_PATH", FRAMEWORK_PATH . "helpers" . DS);
  32.  
  33. define("UPLOAD_PATH", PUBLIC_PATH . "uploads" . DS);
  34.  
  35. // Define platform, controller, action, for example:
  36.  
  37. // index.php?p=admin&c=Goods&a=add
  38.  
  39. define("PLATFORM", isset($_REQUEST['p']) ? $_REQUEST['p'] : 'home');
  40.  
  41. define("CONTROLLER", isset($_REQUEST['c']) ? $_REQUEST['c'] : 'Index');
  42.  
  43. define("ACTION", isset($_REQUEST['a']) ? $_REQUEST['a'] : 'index');
  44.  
  45. define("CURR_CONTROLLER_PATH", CONTROLLER_PATH . PLATFORM . DS);
  46.  
  47. define("CURR_VIEW_PATH", VIEW_PATH . PLATFORM . DS);
  48.  
  49. // Load core classes
  50.  
  51. require CORE_PATH . "Controller.class.php";
  52.  
  53. require CORE_PATH . "Loader.class.php";
  54.  
  55. require DB_PATH . "Mysql.class.php";
  56.  
  57. require CORE_PATH . "Model.class.php";
  58.  
  59. // Load configuration file
  60.  
  61. $GLOBALS['config'] = include CONFIG_PATH . "config.php";
  62.  
  63. // Start session
  64.  
  65. session_start();
  66.  
  67. }

From the comments you can see the purpose of each steps.

Autoloading

We don’t want to manually code include or require for a class file what we need in every script in the project, that’s why PHP MVC frameworks have this autoloading feature. For example, in Symfony, if you put your own class file under ‘lib’ folder, then it will be auto loaded. Magic? No, there is no magic. Let’s implement our autoloading feature in our mini framework.

Here we need to use a PHP built-in function called spl_autoload_register

Hide   Shrink    Copy Code
  1. // Autoloading
  2.  
  3. private static function autoload(){
  4.  
  5. spl_autoload_register(array(__CLASS__,'load'));
  6.  
  7. }
  8.  
  9. // Define a custom load method
  10.  
  11. private static function load($classname){
  12.  
  13. // Here simply autoload app’s controller and model classes
  14.  
  15. if (substr($classname, -10) == "Controller"){
  16.  
  17. // Controller
  18.  
  19. require_once CURR_CONTROLLER_PATH . "$classname.class.php";
  20.  
  21. } elseif (substr($classname, -5) == "Model"){
  22.  
  23. // Model
  24.  
  25. require_once MODEL_PATH . "$classname.class.php";
  26.  
  27. }
  28.  
  29. }

Every framework has a name conversion, ours is no exception. For a controller class, it should be xxxController.class.php, for a model class, it should be xxxModel.class.php. Why for a new framework you come across, you must follow its naming convention? Autoloading is one of the reasons.

Routing/Dispatching

Hide   Copy Code
  1. // Routing and dispatching
  2.  
  3. private static function dispatch(){
  4.  
  5. // Instantiate the controller class and call its action method
  6.  
  7. $controller_name = CONTROLLER . "Controller";
  8.  
  9. $action_name = ACTION . "Action";
  10.  
  11. $controller = new $controller_name;
  12.  
  13. $controller->$action_name();
  14.  
  15. }

In this step, index.php will dispatch the request to the proper Controller::Action() method. It’s very simple here just for an example.

Base Controller class

There is always a base controller class(or several) in the framework’s core classes. For example, In Symfony it’s called sfActions; in iOS it’s called UIViewController. Here we will just name it Controller, the file name is Controller.class.php

Hide   Shrink    Copy Code
  1. <?php
  2.  
  3. // Base Controller
  4.  
  5. class Controller{
  6.  
  7. // Base Controller has a property called $loader, it is an instance of Loader class(introduced later)
  8.  
  9. protected $loader;
  10.  
  11. public function __construct(){
  12.  
  13. $this->loader = new Loader();
  14.  
  15. }
  16.  
  17. public function redirect($url,$message,$wait = 0){
  18.  
  19. if ($wait == 0){
  20.  
  21. header("Location:$url");
  22.  
  23. } else {
  24.  
  25. include CURR_VIEW_PATH . "message.html";
  26.  
  27. }
  28.  
  29. exit;
  30.  
  31. }
  32.  
  33. }

Base Controller has a property called $loader, it is an instance of Loader class(introduced later). Please note the phrase ‘ it is an instance of Loader class’ -- preciously speaking, $this->loader is a reference variable which reference/points to an instance of Load class. We don’t talk more about this here, but this is actually a very important concept. I have met some PHP developers who believe after this statement:

Hide   Copy Code
  1. $this->loader = new Loader();

$this->loader is an object. No, it’s a reference. This term starts from Java, before Java, it’s called pointer in C++ or Objective C. Reference is an encapsulated pointer type. For example, in iOS(Objective-C) we create an object using:

Hide   Copy Code
  1. UIButton *btn = [UIButton alloc] init];

Loader class

In framework.class.php, we have already implemented application’s controller and model class’ autoloading. But how to load classes in the framework directory? Here we can create a new class called Loader, it will be used to load the framework’s classes and functions. When we need to load a framework’s class, just call this Loader class’s method.

Hide   Copy Code
  1. class Loader{
  2.  
  3. // Load library classes
  4.  
  5. public function library($lib){
  6.  
  7. include LIB_PATH . "$lib.class.php";
  8.  
  9. }
  10.  
  11. // loader helper functions. Naming conversion is xxx_helper.php;
  12.  
  13. public function helper($helper){
  14.  
  15. include HELPER_PATH . "{$helper}_helper.php";
  16.  
  17. }
  18.  
  19. }

Implementing Model

We will implement Model in the simplest way, by creating two class files:

Mysql.class.php - this class is under framework/database, it is to encapsulate database connection and some basic SQL query methods.

Model.class.php - this is the Base Model class, it contains methods for all kinds of CRUD

Hide   Shrink    Copy Code
  1. <?php
  2.  
  3. /**
  4.  
  5. *================================================================
  6.  
  7. *framework/database/Mysql.class.php
  8.  
  9. *Database operation class
  10.  
  11. *================================================================
  12.  
  13. */
  14.  
  15. class Mysql{
  16.  
  17. protected $conn = false; //DB connection resources
  18.  
  19. protected $sql; //sql statement
  20.  
  21. /**
  22.  
  23. * Constructor, to connect to database, select database and set charset
  24.  
  25. * @param $config string configuration array
  26.  
  27. */
  28.  
  29. public function __construct($config = array()){
  30.  
  31. $host = isset($config['host'])? $config['host'] : 'localhost';
  32.  
  33. $user = isset($config['user'])? $config['user'] : 'root';
  34.  
  35. $password = isset($config['password'])? $config['password'] : '';
  36.  
  37. $dbname = isset($config['dbname'])? $config['dbname'] : '';
  38.  
  39. $port = isset($config['port'])? $config['port'] : '3306';
  40.  
  41. $charset = isset($config['charset'])? $config['charset'] : '3306';
  42.  
  43. $this->conn = mysql_connect("$host:$port",$user,$password) or die('Database connection error');
  44.  
  45. mysql_select_db($dbname) or die('Database selection error');
  46.  
  47. $this->setChar($charset);
  48.  
  49. }
  50.  
  51. /**
  52.  
  53. * Set charset
  54.  
  55. * @access private
  56.  
  57. * @param $charset string charset
  58.  
  59. */
  60.  
  61. private function setChar($charest){
  62.  
  63. $sql = 'set names '.$charest;
  64.  
  65. $this->query($sql);
  66.  
  67. }
  68.  
  69. /**
  70.  
  71. * Execute SQL statement
  72.  
  73. * @access public
  74.  
  75. * @param $sql string SQL query statement
  76.  
  77. * @return $result,if succeed, return resrouces; if fail return error message and exit
  78.  
  79. */
  80.  
  81. public function query($sql){
  82.  
  83. $this->sql = $sql;
  84.  
  85. // Write SQL statement into log
  86.  
  87. $str = $sql . " [". date("Y-m-d H:i:s") ."]" . PHP_EOL;
  88.  
  89. file_put_contents("log.txt", $str,FILE_APPEND);
  90.  
  91. $result = mysql_query($this->sql,$this->conn);
  92.  
  93. if (! $result) {
  94.  
  95. die($this->errno().':'.$this->error().'<br />Error SQL statement is '.$this->sql.'<br />');
  96.  
  97. }
  98.  
  99. return $result;
  100.  
  101. }
  102.  
  103. /**
  104.  
  105. * Get the first column of the first record
  106.  
  107. * @access public
  108.  
  109. * @param $sql string SQL query statement
  110.  
  111. * @return return the value of this column
  112.  
  113. */
  114.  
  115. public function getOne($sql){
  116.  
  117. $result = $this->query($sql);
  118.  
  119. $row = mysql_fetch_row($result);
  120.  
  121. if ($row) {
  122.  
  123. return $row[0];
  124.  
  125. } else {
  126.  
  127. return false;
  128.  
  129. }
  130.  
  131. }
  132.  
  133. /**
  134.  
  135. * Get one record
  136.  
  137. * @access public
  138.  
  139. * @param $sql SQL query statement
  140.  
  141. * @return array associative array
  142.  
  143. */
  144.  
  145. public function getRow($sql){
  146.  
  147. if ($result = $this->query($sql)) {
  148.  
  149. $row = mysql_fetch_assoc($result);
  150.  
  151. return $row;
  152.  
  153. } else {
  154.  
  155. return false;
  156.  
  157. }
  158.  
  159. }
  160.  
  161. /**
  162.  
  163. * Get all records
  164.  
  165. * @access public
  166.  
  167. * @param $sql SQL query statement
  168.  
  169. * @return $list an 2D array containing all result records
  170.  
  171. */
  172.  
  173. public function getAll($sql){
  174.  
  175. $result = $this->query($sql);
  176.  
  177. $list = array();
  178.  
  179. while ($row = mysql_fetch_assoc($result)){
  180.  
  181. $list[] = $row;
  182.  
  183. }
  184.  
  185. return $list;
  186.  
  187. }
  188.  
  189. /**
  190.  
  191. * Get the value of a column
  192.  
  193. * @access public
  194.  
  195. * @param $sql string SQL query statement
  196.  
  197. * @return $list array an array of the value of this column
  198.  
  199. */
  200.  
  201. public function getCol($sql){
  202.  
  203. $result = $this->query($sql);
  204.  
  205. $list = array();
  206.  
  207. while ($row = mysql_fetch_row($result)) {
  208.  
  209. $list[] = $row[0];
  210.  
  211. }
  212.  
  213. return $list;
  214.  
  215. }
  216.  
  217. /**
  218.  
  219. * Get last insert id
  220.  
  221. */
  222.  
  223. public function getInsertId(){
  224.  
  225. return mysql_insert_id($this->conn);
  226.  
  227. }
  228.  
  229. /**
  230.  
  231. * Get error number
  232.  
  233. * @access private
  234.  
  235. * @return error number
  236.  
  237. */
  238.  
  239. public function errno(){
  240.  
  241. return mysql_errno($this->conn);
  242.  
  243. }
  244.  
  245. /**
  246.  
  247. * Get error message
  248.  
  249. * @access private
  250.  
  251. * @return error message
  252.  
  253. */
  254.  
  255. public function error(){
  256.  
  257. return mysql_error($this->conn);
  258.  
  259. }
  260.  
  261. }

Here is the Model.class.php

Hide   Shrink    Copy Code
  1. <?php
  2.  
  3. // framework/core/Model.class.php
  4.  
  5. // Base Model Class
  6.  
  7. class Model{
  8.  
  9. protected $db; //database connection object
  10.  
  11. protected $table; //table name
  12.  
  13. protected $fields = array(); //fields list
  14.  
  15. public function __construct($table){
  16.  
  17. $dbconfig['host'] = $GLOBALS['config']['host'];
  18.  
  19. $dbconfig['user'] = $GLOBALS['config']['user'];
  20.  
  21. $dbconfig['password'] = $GLOBALS['config']['password'];
  22.  
  23. $dbconfig['dbname'] = $GLOBALS['config']['dbname'];
  24.  
  25. $dbconfig['port'] = $GLOBALS['config']['port'];
  26.  
  27. $dbconfig['charset'] = $GLOBALS['config']['charset'];
  28.  
  29. $this->db = new Mysql($dbconfig);
  30.  
  31. $this->table = $GLOBALS['config']['prefix'] . $table;
  32.  
  33. $this->getFields();
  34.  
  35. }
  36.  
  37. /**
  38.  
  39. * Get the list of table fields
  40.  
  41. *
  42.  
  43. */
  44.  
  45. private function getFields(){
  46.  
  47. $sql = "DESC ". $this->table;
  48.  
  49. $result = $this->db->getAll($sql);
  50.  
  51. foreach ($result as $v) {
  52.  
  53. $this->fields[] = $v['Field'];
  54.  
  55. if ($v['Key'] == 'PRI') {
  56.  
  57. // If there is PK, save it in $pk
  58.  
  59. $pk = $v['Field'];
  60.  
  61. }
  62.  
  63. }
  64.  
  65. // If there is PK, add it into fields list
  66.  
  67. if (isset($pk)) {
  68.  
  69. $this->fields['pk'] = $pk;
  70.  
  71. }
  72.  
  73. }
  74.  
  75. /**
  76.  
  77. * Insert records
  78.  
  79. * @access public
  80.  
  81. * @param $list array associative array
  82.  
  83. * @return mixed If succeed return inserted record id, else return false
  84.  
  85. */
  86.  
  87. public function insert($list){
  88.  
  89. $field_list = ''; //field list string
  90.  
  91. $value_list = ''; //value list string
  92.  
  93. foreach ($list as $k => $v) {
  94.  
  95. if (in_array($k, $this->fields)) {
  96.  
  97. $field_list .= "`".$k."`" . ',';
  98.  
  99. $value_list .= "'".$v."'" . ',';
  100.  
  101. }
  102.  
  103. }
  104.  
  105. // Trim the comma on the right
  106.  
  107. $field_list = rtrim($field_list,',');
  108.  
  109. $value_list = rtrim($value_list,',');
  110.  
  111. // Construct sql statement
  112.  
  113. $sql = "INSERT INTO `{$this->table}` ({$field_list}) VALUES ($value_list)";
  114.  
  115. if ($this->db->query($sql)) {
  116.  
  117. // Insert succeed, return the last record’s id
  118.  
  119. return $this->db->getInsertId();
  120.  
  121. //return true;
  122.  
  123. } else {
  124.  
  125. // Insert fail, return false
  126.  
  127. return false;
  128.  
  129. }
  130.  
  131. }
  132.  
  133. /**
  134.  
  135. * Update records
  136.  
  137. * @access public
  138.  
  139. * @param $list array associative array needs to be updated
  140.  
  141. * @return mixed If succeed return the count of affected rows, else return false
  142.  
  143. */
  144.  
  145. public function update($list){
  146.  
  147. $uplist = ''; //update fields
  148.  
  149. $where = 0; //update condition, default is 0
  150.  
  151. foreach ($list as $k => $v) {
  152.  
  153. if (in_array($k, $this->fields)) {
  154.  
  155. if ($k == $this->fields['pk']) {
  156.  
  157. // If it’s PK, construct where condition
  158.  
  159. $where = "`$k`=$v";
  160.  
  161. } else {
  162.  
  163. // If not PK, construct update list
  164.  
  165. $uplist .= "`$k`='$v'".",";
  166.  
  167. }
  168.  
  169. }
  170.  
  171. }
  172.  
  173. // Trim comma on the right of update list
  174.  
  175. $uplist = rtrim($uplist,',');
  176.  
  177. // Construct SQL statement
  178.  
  179. $sql = "UPDATE `{$this->table}` SET {$uplist} WHERE {$where}";
  180.  
  181. if ($this->db->query($sql)) {
  182.  
  183. // If succeed, return the count of affected rows
  184.  
  185. if ($rows = mysql_affected_rows()) {
  186.  
  187. // Has count of affected rows
  188.  
  189. return $rows;
  190.  
  191. } else {
  192.  
  193. // No count of affected rows, hence no update operation
  194.  
  195. return false;
  196.  
  197. }
  198.  
  199. } else {
  200.  
  201. // If fail, return false
  202.  
  203. return false;
  204.  
  205. }
  206.  
  207. }
  208.  
  209. /**
  210.  
  211. * Delete records
  212.  
  213. * @access public
  214.  
  215. * @param $pk mixed could be an int or an array
  216.  
  217. * @return mixed If succeed, return the count of deleted records, if fail, return false
  218.  
  219. */
  220.  
  221. public function delete($pk){
  222.  
  223. $where = 0; //condition string
  224.  
  225. //Check if $pk is a single value or array, and construct where condition accordingly
  226.  
  227. if (is_array($pk)) {
  228.  
  229. // array
  230.  
  231. $where = "`{$this->fields['pk']}` in (".implode(',', $pk).")";
  232.  
  233. } else {
  234.  
  235. // single value
  236.  
  237. $where = "`{$this->fields['pk']}`=$pk";
  238.  
  239. }
  240.  
  241. // Construct SQL statement
  242.  
  243. $sql = "DELETE FROM `{$this->table}` WHERE $where";
  244.  
  245. if ($this->db->query($sql)) {
  246.  
  247. // If succeed, return the count of affected rows
  248.  
  249. if ($rows = mysql_affected_rows()) {
  250.  
  251. // Has count of affected rows
  252.  
  253. return $rows;
  254.  
  255. } else {
  256.  
  257. // No count of affected rows, hence no delete operation
  258.  
  259. return false;
  260.  
  261. }
  262.  
  263. } else {
  264.  
  265. // If fail, return false
  266.  
  267. return false;
  268.  
  269. }
  270.  
  271. }
  272.  
  273. /**
  274.  
  275. * Get info based on PK
  276.  
  277. * @param $pk int Primary Key
  278.  
  279. * @return array an array of single record
  280.  
  281. */
  282.  
  283. public function selectByPk($pk){
  284.  
  285. $sql = "select * from `{$this->table}` where `{$this->fields['pk']}`=$pk";
  286.  
  287. return $this->db->getRow($sql);
  288.  
  289. }
  290.  
  291. /**
  292.  
  293. * Get the count of all records
  294.  
  295. *
  296.  
  297. */
  298.  
  299. public function total(){
  300.  
  301. $sql = "select count(*) from {$this->table}";
  302.  
  303. return $this->db->getOne($sql);
  304.  
  305. }
  306.  
  307. /**
  308.  
  309. * Get info of pagination
  310.  
  311. * @param $offset int offset value
  312.  
  313. * @param $limit int number of records of each fetch
  314.  
  315. * @param $where string where condition,default is empty
  316.  
  317. */
  318.  
  319. public function pageRows($offset, $limit,$where = ''){
  320.  
  321. if (empty($where)){
  322.  
  323. $sql = "select * from {$this->table} limit $offset, $limit";
  324.  
  325. } else {
  326.  
  327. $sql = "select * from {$this->table} where $where limit $offset, $limit";
  328.  
  329. }
  330.  
  331. return $this->db->getAll($sql);
  332.  
  333. }
  334.  
  335. }

Now we can create a User model class in our application folder, this is for our User table in the database. The code would look like this:

Hide   Copy Code
  1. <?php
  2.  
  3. // application/models/UserModel.class.php
  4.  
  5. class UserModel extends Model{
  6.  
  7. public function getUsers(){
  8.  
  9. $sql = "select * from $this->table";
  10.  
  11. $users = $this->db->getAll($sql);
  12.  
  13. return $users;
  14.  
  15. }
  16.  
  17. }

And our application’s backend indexController could be look like this:

Hide   Shrink    Copy Code
  1. <?php
  2.  
  3. // application/controllers/admin/IndexController.class.php
  4.  
  5. class IndexController extends BaseController{
  6.  
  7. public function mainAction(){
  8.  
  9. include CURR_VIEW_PATH . "main.html";
  10.  
  11. // Load Captcha class
  12.  
  13. $this->loader->library("Captcha");
  14.  
  15. $captcha = new Captcha;
  16.  
  17. $captcha->hello();
  18.  
  19. $userModel = new UserModel("user");
  20.  
  21. $users = $userModel->getUsers();
  22.  
  23. }
  24.  
  25. public function indexAction(){
  26.  
  27. $userModel = new UserModel("user");
  28.  
  29. $users = $userModel->getUsers();
  30.  
  31. // Load View template
  32.  
  33. include CURR_VIEW_PATH . "index.html";
  34.  
  35. }
  36.  
  37. public function menuAction(){
  38.  
  39. include CURR_VIEW_PATH . "menu.html";
  40.  
  41. }
  42.  
  43. public function dragAction(){
  44.  
  45. include CURR_VIEW_PATH . "drag.html";
  46.  
  47. }
  48.  
  49. public function topAction(){
  50.  
  51. include CURR_VIEW_PATH . "top.html";
  52.  
  53. }
  54.  
  55. }

So far, our application backend’s Index controller is working, it communicates with Model and passes result variable to the View templates, so it can be rendered in the browser.

This is a very brief introduction to a mini MVC framework, hope it clarifies some basic concepts in the MVC frameworks.

【转】Code Your Own PHP MVC Framework in 1 Hour的更多相关文章

  1. Spring MVC Framework 注解

    ControllerAdvice Spring MVC Framework会把 @ControllerAdvice注解内部使用 @ExceptionHandler.@InitBinder.@Model ...

  2. Karma - MVC Framework for Unity3D

    Karma is an MVC framework for Unity3D. Because of how Unity is structured, it actually turns out to ...

  3. How to create a site with AJAX enabled in MVC framework.

    How to create a site with AJAX enabled in MVC framework. The Project illustrates how to create a web ...

  4. Code First :使用Entity. Framework编程(8) ----转发 收藏

    第8章 Code First将走向哪里? So far, this book has covered all of the Code First components that reached the ...

  5. Code First :使用Entity. Framework编程(7) ----转发 收藏

    第7章 高级概念 The Code First modeling functionality that you have seen so far should be enough to get you ...

  6. 理解ASP.NET MVC Framework Action Filters

    原文:http://www.cnblogs.com/darkdawn/archive/2009/03/13/1410477.html 本指南主要解释action filters,action filt ...

  7. WebWork2和Spring MVC Framework的比较

    http://daihaixiang.blog.163.com/blog/static/3830134200711411515336/ WebWork2和Spring MVC Framework的比较 ...

  8. ASP.NET MVC Framework

    ASP.NET MVC Framework是微软在ASP.NET中所添加的一组类库,这组类库可以使用Model-View-Controller的设计模式来开发ASP.NET的应用程序.它与现有的ASP ...

  9. TreeFrog Framework : High-speed C++ MVC Framework for Web Application http://www.treefrogframework.org

    TreeFrog Framework : High-speed C++ MVC Framework for Web Application http://www.treefrogframework.o ...

随机推荐

  1. python:post请求业务、调用微信api监控业务

    vim post.py #!/usr/bin/env python # -*- coding: utf-8 -*- import json import os import datetime impo ...

  2. 【REDIS】 redis-cli 命令

    Redis提供了丰富的命令(command)对数据库和各种数据类型进行操作,这些command可以在Linux终端使用. 在编程时,比如使用Redis 的Java语言包,这些命令都有对应的方法.下面将 ...

  3. python 学习第二周总复习

    目录 数据类型内置方法 数字类型内置方法 整型 浮点型 字符串类型内置方法 列表类型内置方法 元祖类型内置方法 字典类型内置方法 集合类型内置方法 布尔类型 数据类型总结 拷贝 浅拷贝 深拷贝 053 ...

  4. linux-命令学习-1

    1. cat命令 http://blog.csdn.net/jackalfly/article/details/7556848 cat主要有三大功能:1.一次显示整个文件.$ cat   filena ...

  5. Maven运行报错:-Dmaven.multiModuleProjectDirectory system propery is not set.

    eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery is ...

  6. 【01】报错:webpack 不是内部或不可执行命令

    [02] webpack 不是内部或不可执行命令 一般来安装完之后是可以直接执行的你可以执行 webpack -v 或者是 webpack --help   这样的就是正确的,我的问题的解决办法是 将 ...

  7. vmware安装CentOS " Intel VT-x 处于禁用状态"

    我刚用虚拟机vmware 11安装CentOS 7 ,出现错误“此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态”的问题,如下图. Intel VT-x 即Virtualiza ...

  8. IndiaHacks 2nd Elimination 2017 (unofficial, unrated mirror, ICPC rules)

    D. Airplane Arrangements time limit per test 2 seconds memory limit per test 256 megabytes input sta ...

  9. 快速排序php

    <?php /** * Created by PhpStorm. * User: brady.wang * Date: 2017/11/10 * Time: 9:45 */ $arr=array ...

  10. nginx 的日志切割

    nginx的日志切割脚本 说明:在nginx的配置文件中nginx.conf并没有定义access_log的位置, 在/usr/local/nginx/conf/vhost/下的配置文件中定义了acc ...