A gentle introduction to MVC (part 3)
This article was written by nemetral.
Voices matter! Please feel free to share your opinion, ask for more explanations or point out divergences using comments.
No time to read this now? Bookmark it and come back later..
In part 1, we decoupled a vanilla PHP script and separated the business logic from the presentation. In part 2, we added a third element in the mix called the model and dedicated to the data access layer. It is now time to spice up the coding by introducing the role of Object-Oriented Programming in a MVC architecture and release the very basis (for educational purpose only) of a MVC framework.
Part 3: OOPs I’ve added objects
As you all know, OOP is famous for wrapping functions and variables into higher-level elements called objects (if you’re not familiar with OOP, I suggest you have a look at the Wikipedia page and some tutorials). So here is how we could merge MVC and OOP for a greater code flexibility, reusability and maintainability:
- the controller is an object: in CodeIgniter for example, the first segment of the URL is the name of the controller’s object and the second segment is the name of the controller’s method which needs to be run (for example, calling
http://community.com/members/showwould trigger the instantiation of themembersobject and the call of theshowmethod) - the model is an object: as a representation and abstraction of the data, the model is also an object (let’s call it
members_model) and contains functions such asgetAllMembers()for example - the view can be an object too: with general functions such as
getTemplate()which selects the corresponding template orrenderHTMLPage()which fills the HTML page with the data and outputs the result; but the templates (and sub-templates) are plain PHP/HTML files (let’s call the layout templatemembers_view.php) - the router is a plain vanilla PHP file which essentially checks the validity of the request and loads the correct controller
Now if we translate these principles into actual PHP code, here is what a very raw MVC framework could look like (directly inspired from CodeIgniter):
Tree structure:
index.php
/controllers
members.php
/models
members_model.php
/views
members_view.php
/tpl
header.php
file: index.php
<?php
$request = preg_replace("|/*(.+?)/*$|", "\\1", $_SERVER['PATH_INFO']);
$uri = explode('/', $request);
include 'controllers/' . $uri[0] . '.php';
$controller = new $uri[0];
$controller->{$uri[1]}();
?>
index.phpis called in the URL- takes the
PATH_INFO(here: /members/show/) and cleans the starting and trailing slashes using a REGEX - explodes the URL into
$uri[0](name of the requested controller) and$uri[1](name of the requested method) - instanciates the controller and calls the method
file: controllers/members.php
<?php
class members
{
function show() {
include 'models/members_model.php';
$model = new members_model();
$members = $model->getAllMembers();
include 'views/members_view.php';
}
}
?>
- to simplify, there is no constructor and the function
show()is directly run - the method
show()loads and instanciates the correct model, calls the method to get all the members and fills the$membersvariable with the data - then the method
show()loads the correct view: the latter is automatically parsed (the data contained in the$membersvariable is inserted in-between HTML tags) and output
file: models/members_model.php
<?php
class members_model
{
function members_model() {
$connection = mysql_connect('host', 'user', 'password');
mysql_select_db('database', $connection);
}
function getAllMembers() {
$data = mysql_query('SELECT name FROM members');
$members = array();
while ($item = mysql_fetch_array($data)) {
$members[] = $item['name'];
}
return $members;
}
}
- there is a constructor establishing once for all the connection to the database
- the method
getAllMembers()queries the database, extracts the members’ names and returns them through an array
file: views/members_view.php
<html>
<?php include 'views/tpl/header.php'; ?>
<h1>Members of community.com:</h1>
<ul>
<?php for ($i = 0; $i < count($members); $i++) : ?>
<li>Member #<?php echo $i + 1; ?>: <?php echo $members[$i]; ?></li>
<?php endfor; ?>
</ul>
</html>
file: views/tpl/header.php
<head> <title>Community.com rocks!</title> </head>
- the main layout
members_view.phpis included by the controller and therefore automatically parsed - the layout includes a reusable template for the header
Note: this code is for educational purpose only.
As you can see, building a OO MVC architecture is not that difficult. Please bear in mind that the code above is a basic way of achieving a MVC architecture and a lot of things could be improved:
- first thing to do is to dramatically enhance the router file: there is no checking on whether the requested controller exists or not, and is accessible or not (this is a huge security hole)
- instead of getting connected to the database in the model’s constructor, why not creating a model superclass managing the database connection and make each model an extension of this superclass? This way we could use several models from our controller without worrying about being already connected to the database or not
- in the same way, why not creating a controller superclass with common features and make each controller an extension of this superclass?
Now CodeIgniter has all that.. and much more. It is secure, lightweight and brillantly coded. If you want to start coding MVC, CodeIgniter is a must have!


16
October 30th, 2008
1:11 am
Hi!
Thanks for this tutorial! I’m really happy you’ve shared this knowledge.
Thanks!
January 30th, 2009
8:20 pm
Well…very amazing…
How is the division of archives of image, js, css?
Thanks..
January 30th, 2009
11:25 pm
@Maicon: images, js and css all belong to the Views (same level as HTML) so you can insert them in subfolders inside your Views folder. But there is better: you can also put them at the root of your website so as to shorten include paths (like http://example.com/img/image.jpg instead of http://example.com/engine/views/img/image.jpg). To be honest, images, css and js can be put wherever you want as long as they are correctly linked to.
February 4th, 2009
8:26 pm
So, okay, at what level of website complexity does this actually become useful? I mean, I make websites for small- to medium-sized businesses, which generally translates to small- to medium-sized sites, typically with no database integration. Is it fair to say that it’s not helpful to go to such extremes to create simple brochure sites?
February 5th, 2009
12:45 am
@Scott: you are absolutely right. Each project deserves its own kind of coding. Brochure websites surely don’t need MVC. For blogs, Wordpress is surely what most people need (Wordpress is not MVC). This series of posts was rather aimed at explaining how to tackle a very specific project, with database integration, that doesn’t fit in any pre-thought types of websites; and how to tackle it using clean code.
February 5th, 2009
5:35 pm
Cool, thanks!
February 16th, 2009
2:48 am
It’s interesting that you have the index directly instantiate a class, instead of an interface. Perhaps not the best way to implement OOP. Do you have a class diagram of the example system that you’re describing? Not enough people design class diagrams before they try to design an MVC architecture, but upon designing one, alot of things become clear. I’d be interested to view a class diagram to gain a greater perspective on what you’re trying to describe
February 17th, 2009
11:26 pm
@Mike: this 3rd post about MVC is simply aimed at detailing how to put together a very raw and very basic MVC workflow. In this example, I wanted to emphasize the role of a router instantiating classes based on requested URLs: that’s what index.php does. But as explained in the conclusion, this example is simply an illustration of the workflow and is not secure.
February 25th, 2009
10:32 pm
MemberController in class, as if I would not want to include ‘view/members_view.php’;, do this so automatically, any suggestions? Thanks
February 26th, 2009
11:02 pm
@Maicon: sorry I don’t quite understand your question there. Could you explain a little more? Cheers.
February 27th, 2009
7:32 pm
Ok, Sorry. I will go try again.
In your example of mvc, the view (members_view.php) file was included in the class membersController, see below:
class membersController {
// action
include ‘view/members_view.php’;
}
How I remove this include? see below:
class membersController {
function members {
$members = $model->getAllMembers();
}
//no file include
}
members_view.php
Thank you very much!
February 27th, 2009
7:41 pm
Full Example:
class membersController {
function members() {
$members = $this->model->getAllMembers();
}
// no file de include the view
}
membersView.php
I tried to do using the function _autoload(),
but without success.
March 15th, 2009
5:19 pm
@Maicon: the include there is simply aimed at sending the HTML output to the browser once filled with the variables. I don’t exactly understand why including the view there bugs you at all. A lot of MVC frameworks have special methods to send the HTML to the browser but these are just abstractions of a plain old include.. Here I wanted to KISS so I let the include function in the example. If you really want to include the view file outside of the class then you could work out an inclusion in the very first “index.php” file but that’s not supposed to be its place at all!
March 27th, 2009
6:59 pm
Hello,
Love the advice etc you give here. Not sure I fully understand what Mike meant by instantiating an interface instead of a class, could you clarify?
Thanks!
April 29th, 2009
3:32 pm
A very good article. I’ve enjoyed reading it. It would have been helpfull to have had a download link with the example files on page 3 (instead of having to copy and paste it). It makes for a great piece of code to start experimenting with.