Documente Academic
Documente Profesional
Documente Cultură
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
Home
Coding
Photography
About
Home Coding MySQL PHP Start your own MVC Framework with PHP
Tweet
Like
14
Share
I have been using ASP .NET MVC for many years. It is a complex
framework but not dicult to learn (at least for .NET developers).
Anyway, I like the way it handles templates and routing. Few
years ago, one of my clients asked me to developed a simple ERP
system with PHP and MySQL. My rst thought was: "Why not
developing a simple MVC framework with PHP?". It would allow
me to utilise the backend code and avoid mixing code in classes.
I started to study many PHP MVC Frameworks such as Zend
Framework, Symfony and CakePHP but I realised those "ready-to-use" frameworks are
overkilled for this simple project and I would like to have codes that I could manipulate easily and
apply them to next simple projects without making my brand hurts.
Luckily, I found this article: Write your own PHP MVC Framework. It is a very good article and it
explained the concept of MVC comprehensively. If you just start learning MVC, this is a great
place start. Well, the truth is the article inspired me to create my own little MVC framework with
PHP.
Anyway, before you continue reading, I recommend you to read through the article I mentioned
above. My version of MVC is a little bit dierent from Anant Garg's but I believe you will nd it
useful.
In this article, I would like to focus on the routing and template operations. Since Anant Garg has
covered most important parts of MVC, I will just point out some features of my own framework in
this article.
1 of 18
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
Before we start talking about the details, let's have a look at the directory structure. You can
expand the folder below and link to sample codes of this article. The structure is pretty much the
same as Anant Garg's. The only dierence is that I put all public assessable les (images, style
sheets and js scripts) into public folder.
htdocs
application
cong
library
public
.htaccess
htdocs/.htaccess
1
2
3
4
5
6
7
8
Options +FollowSymLinks
<ifmodule mod_rewrite.c="">
# Tell PHP that the mod_rewrite module is ENABLED.
SetEnv HTTP_MOD_REWRITE On
RewriteEngine on
RewriteRule ^$
public/
[L]
RewriteRule (.*) public/$1 [L]
</ifmodule>
In the root of the public folder, we have another .htaccess waiting for us to process the requests
(sample below). We put every public accessible les into the public folder, so it is much easier to
organise them in the future. If the requests are images, videos, style sheets or script les,
then we just feed them to clients directly. If the request is the actual page, then we parse the URL
and let the /public/index.php to handle the rest of actions. The actual URL and query strings
are assigned to _route variable.
/public/.htaccess
1
2
3
2 of 18
Options +FollowSymLinks
<ifmodule mod_rewrite.c="">
# Tell PHP that the mod_rewrite module is ENABLED.
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
4
5
6
7
8
9
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
SetEnv HTTP_MOD_REWRITE On
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?_route=$1?%{QUERY_STRING} [PT,L]
</ifmodule>
Once we have an actual page request, then our MVC bootstrap process starts from here. The only
dierence here between Anant Garg's code is we need to get the original query strings since PHP
parses the query string to be part of URL entity.
/public/index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
// Ensure we have session
if(session_id() === ""){
session_start();
}
// the routing url, we need to use original 'QUERY_STRING' from server paramater beca
$_route = isset($_GET['_route']) ? preg_replace('/^_route=(.*)/','$1',$_SERVER
// start to dispatch
require_once (ROOT . DS . 'library' . DS . 'bootstrap.php');
Bootstrap
Basically, this part does not have big dierences between Anant Garg's concept. The dierences
are:
I included a cong.php le to serve conguration parameters such as site name and title
I use spl_autoload_register instead of __autoload (Please refer this discussion)
I wrapped the "removeMagicQuotes" and "unregisterGlobals" functions to MyHelpers
class
I use use the Router class to handle further operations and dispatch the outputs
I call session_write_close and the end of the operation to unlock the session data. This is
useful when you have many concurrent connections such as using Ajax operations.
/library/bootstrap.php
1
2
3
4
5
6
3 of 18
<?php
// Ensure we have session
if(session_id() === ""){
session_start();
}
// the config file path
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
4 of 18
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
});
library/core directory
= $rootPath . 'library' . DS . 'core'
library/mvc directory
= $rootPath . 'library' . DS . 'mvc'
application/controllers directory
= $rootPath . 'application' . DS .
application/models directory
= $rootPath . 'application' . DS .
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
5 of 18
<?php
class Router
{
protected $_controller,
$_action,
$_view,
$_params,
$_route;
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
6 of 18
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
$path = $this->_route;
// the rules to route
$cai = '/^([\w]+)\/([\w]+)\/([\d]+).*$/'; //
$ci =
'/^([\w]+)\/([\d]+).*$/';
//
$ca =
'/^([\w]+)\/([\w]+).*$/';
//
$c =
'/^([\w]+).*$/';
//
$i =
'/^([\d]+).*$/';
//
// initialize the matches
$matches = array();
// if this is home page route
if (empty($path)){
$this->_controller = 'index';
$this->_action = 'index';
} else if (preg_match($cai, $path, $matches)){
$this->_controller = $matches[1];
$this->_action = $matches[2];
$id = $matches[3];
} else if (preg_match($ci, $path, $matches)){
$this->_controller = $matches[1];
$id = $matches[2];
} else if (preg_match($ca, $path, $matches)){
$this->_controller = $matches[1];
$this->_action = $matches[2];
} else if (preg_match($c, $path, $matches)){
$this->_controller = $matches[1];
$this->_action = 'index';
} else if (preg_match($i, $path, $matches)){
$id = $matches[1];
}
controller/action/id
controller/id
controller/action
action
id
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
7 of 18
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
}
// set param id to the id we have
if(!empty($id)){
$this->_params['id']=$id;
}
if($this->_controller == 'index'){
$this->_params = array($this->_params);
}
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
$key = $p[$i]->getName();
if(array_key_exists($key,$params_old)){
$params_new[$i] = $params_old[$key];
unset($params_old[$key]);
}
}
// after reorder, merge the leftovers
$params_new = array_merge($params_new, $params_old);
// call the action method
$this->_view = call_user_func_array(array($dispatch, $m), $params_new
// finally, we print it out
if($this->_view){
echo $this->_view;
}
8 of 18
<?php
class Controller {
protected $_model,
$_controller,
$_action;
public
$cfg,
$view,
$table,
$id,
$db,
$userValidation;
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
9 of 18
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
global $cfg;
// set config
$this->cfg = $cfg;
// construct MVC
$this->_controller = $controller;
$this->_action = $action;
// initialise the template class
$this->view = new Template($controller, $action);
// call the function for derived class
$this->init();
// start contruct models
$this->_model = new $model($this->db);
$this->_model->controller = $this;
$this->table = $controller;
/**
* Initialize the required classes and variables
*/
protected function init(){
/* Put your code here*/
}
/**
* Redirect to action
*/
public function redirectToAction($action, $controller = false, $params
if($controller === false){
$controller = get_called_class();
}else if(is_string($controller) && class_exists($controller.'Controller'
$controller = $controller.'Controller';
$controller = new $controller();
}
return call_user_func_array(array($controller, $action), $params
}
/**
* process default action view
*/
public function defaultAction($params = null){
// make the default action path
$path = MyHelpers::UrlContent("~/views/{$this->_controller}/{$this->_action}.
// if we have action name
if(file_exists($path)){
$this->view->viewPath = $path;
}else{
$this->unknownAction();
}
// if we have parameters
if(!empty($params) && is_array($params)){
// assign local variables
foreach($params as $key=>$value){
$this->view->set($key, $value);
}
}
// dispatch the result
return $this->view();
}
/**
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
* unknownAction
*/
public function unknownAction($params = array()){
// feed 404 header to the client
header("HTTP/1.0 404 Not Found");
// find custom 404 page
$path = MyHelpers::UrlContent("~/views/shared/_404.php");
// if we have custom 404 page, then use it
if(file_exists($path)){
$this->view->viewPath = $path;
return $this->view();
}else{
exit; //Do not do any more work in this script.
}
}
/**
* set the variables
*/
public function set($name,$value) {
// set the parameters to the template class
$this->view->set($name, $value);
}
/**
* Returns the template result
*/
public function view(){
// dispatch the result of the template class
return $this->view;
}
10 of 18
<?php
class Model{
protected $_model;
public $db, $controller;
/**
* Constructor for Model
*
*/
public function __construct($db) {
$this->db = $db;
$this->_model = get_class($this);
$defaultModel = ($this->_model=='Model');
if(!$defaultModel){
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
16
17
18
19
20
21
22
23
24
25
}
}
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
$this->init();
11 of 18
<?php
class Template {
protected $_variables = array(),
$_controller,
$_action,
$_bodyContent;
public
$viewPath,
$section = array(),
$layout;
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
12 of 18
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
*/
public function setAction($action){
$this->_action = $action;
}
/**
* RenderBody
*/
public function renderBody(){
// if we have content, then deliver it
if(!empty($this->_bodyContent)){
echo $this->_bodyContent;
}
}
/**
* RenderSection
*/
public function renderSection($section){
if(!empty($this->section) && array_key_exists($section, $this->section)){
echo $this->section[$section];
}
}
/**
* Display Template
*/
public function render() {
// extract the variables for view pages
extract($this->_variables);
// the view path
$path = MyHelpers::UrlContent('~/views/');
// start buffering
ob_start();
// render page content
if(empty($this->viewPath)){
include ($path . $this->_controller . DS . $this->_action . '.php'
}else{
include ($this->viewPath);
}
// get the body contents
$this->_bodyContent = ob_get_contents();
// clean the buffer
ob_end_clean();
// check if we have any layout defined
if(!empty($this->layout) && (!MyHelpers::isAjax())){
// we need to check the path contains app prefix (~)
$this->layout = MyHelpers::UrlContent($this->layout);
// start buffer (minify pages)
ob_start('MyHelpers::minify_content');
// include the template
include($this->layout);
}else{
ob_start('MyHelpers::minify_content_js');
// just output the content
echo $this->_bodyContent;
}
// end buffer
ob_end_flush();
}
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
89
90
91
92
93
94
95
96
97
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
/**
* return the renderred html string
*/
public function __toString(){
$this->render();
return '';
}
<html>
<head>
<?php $this->renderSection('head');?>
</head>
<body>
<?php $this->renderBody();?>
</body>
</html>
When you put your content of the page, you can also place sections to dened place in the
_defaultLayout.php
/application/view/index/index.php
1
2
3
4
5
6
7
?
<?php
// The default layout template
$this->layout = '~/views/shared/_defaultLayout.php';
// The value to put on the head section
$this->section['head']="<script src='http://code.jquery.com/jquery-latest.min.js
?>
<strong>This is the text I want to show in the body</strong>
13 of 18
<html>
<head>
<script src='http://code.jquery.com/jquery-latest.min.js'></script>
</head>
<body>
<strong>This is the text I want to show in the body</strong>
</body>
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
8
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
</html>
In conclusion, the concept is not dicult and should be easy to apply on any simple project. If
you understand how Anant Garg wants to achieve, you should be able to comprehend this post.
You can download the sample code from HERE for further reading. The sample has more
implementations on this simple MVC framework.
Update: I have updated the MySqlDataAdapter.class.php in the sample code which replaced
mysql_* functions to PDO (PHP Data Objects).
548
by Elvis Hsu
Newer Post
14 of 18
Home
Older Post
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
15 Comments
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
Share
Recommend
Login
Sort by Best
a month ago
Hi, thanks for your tutorial..,i downloaded and it run succesfull. but can you teach me how
to use ajax request in this framework??
Reply Share
Elvis Hsu
Mod
TraxoutMedia
a year ago
Nice code for the most part. I understand that you followed a lot of what Anant
Garg did in his article. Unfortunately that article is from 2009 and the mysql_ api that he
and you both used to write your sql queries is deprecated and has been deprecated for
some time now. It's going to be removed in future updates if it hasn't been already.
Reply Share
Elvis Hsu
Mod
Hi,
Thank you for your valuable comment. I will be changing the MySqlDataAdapter
class from mysql_* to PDO in order to support PHP 5.1+
Cheers,
Elvis
Reply Share
16 days ago
hi, really a good things for biggner..this is easy and really very easy top understand i
created another controller, but i got some error.Call to undefined method Model::read()
what can i do?
Reply Share
luzan
20 days ago
Hi, thanks for your tutorial, I am thinking of applying this structure in different project, what
changes i may have to make.
15 of 18
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
Popular Posts
My Codility test
experience
I've just recently
relocated from
Australia to
Switzerland. Other
than learning German, looking for
a job is one of my big tasks as ...
Start your own MVC
Framework with PHP
I have been using
ASP .NET MVC for
many years. It is a
complex framework
but not dicult to learn (at least
for .NET developers). An...
Issue with "Don't
track your own
pageviews"
Do you use your own
domain name with
Blogger? Do you
place " Blogger's Stats Widget "
on your page? Or do you regularly
chec...
Suggestions to pass
the Professional
Scrum Master I (PSM
I) assessment
I have just recently
passed my PSM I
certicate test from Scrum.org .
Luckily my score was 95% at rst
attempt so I would like to shar...
Dynamic GridPanel
for ExtJs 4
Recently, I was trying
to update our internal
system from ExtJs 3
to version 4. Well, I
think many V3 plugins are needed
to be updated...
16 of 18
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
Categories
Coding ( 17 )
Tips ( 11 )
Javascript ( 8 ) C# ( 6 ) ExtJs
( 6 ) NETCF ( 5 ) Windows Mobile
( 5 ) Blogger ( 4 ) PHP ( 4 ) Linux
( 3 ) MySQL ( 3 ) Ubuntu ( 3 )
Buy me a cuppa
Thank you for visiting my blog.
If you'd like to support me,
you can buy me a cuppa.
Blog Archive
Websites I Like
2014 (7)
Leonteq Securities AG
Code Project
Coiure Bcheler
17 of 18
06/04/2015 09:09 PM
Start your own MVC Framework with PHP ~ Elvis is still in...
126,110
2013 (6)
2012 (4)
2011 (14)
http://www.elvishsu66.com/2014/01/start-your-own-mvc...
Blogs I Follow
Lifehacker
Fabulous Adventures In
Coding
Search Engine Roundtable
Strobist
Scott Hanselman's
Computer Zen
Koding Blog
Sencha Blog
Coding Horror
The Geek Stu
Code it Pretty
About Me
E LV I S H S U
Follow
87
Elvis is
specialised in
advanced object
oriented languages and
enterprise integrated solutions
with extensive experience in
.NET technologies, web
applications, database
developments, complex multiplatform distributed systems and
software project management.
V IE W M Y C O M PL E TE
PROFILE
About | Site Map | Powered by Blogger
2015 Elvis is still in the building
18 of 18
06/04/2015 09:09 PM