MVC in PHP tutorial part 1: Hello World

By Tom Butler

08 Sept 2010

Introduction

A basic implementation demonstration of Model-View-Controller (MVC) in PHP.

Since writing my article Model-View-Confusion part 1: The View gets its own data from the Model I have received several e-mails asking me to provide a simple example of MVC in PHP. So I've decided to create one. However, my intent is to build up from a very simplistic example and include some of the reasoning behind certain design decisions and considerations involved in deploying MVC on the web.

As stated in my previous article, a lot of other tutorials/articles go off into irrelevant sub-topics. I want to cover pure MVC. As such, you'll find no discussion of template engines, directory structures, DAO, ORMs or similar in this article. This is pure MVC. From the ground up I'll explain the original implementation of MVC and why it has to be adapted to work on the web.

What is MVC?

This is a broad definition of the components as defined by the pattern. Later on I will describe variants of this but this is MVC as described by the original implementations in Smalltalk-80

The Model

In its simplest form the model stores data which is to be accessed by the view and written to by the controller.

The model is the most complex of all the parts of the system and will contain all the logic which is specific to the application and where domain entities which relate to real world concepts (such as "a user" or "an order") are stored. It is the part of the application which takes data (from any source) and processes it. The model also handles all data access and storage. It has no knowledge of any controllers or views which may use it.

For example, in PHP the model may represent a "User" in the system. It will handle any operations regarding users. Saving/loading records, validating registrations.

The model is not (common mistakes made by those misinterpreting the pattern):

  • A simple data access point
  • A class called "model" which represents a single database table

The View

The view contains all the display logic. In PHP it will be the part of the application which generates the HTML. It has direct access to the Model and can query the model to get its data. It can create callbacks to its controller (for example a clicking a button in the view would trigger an action in the controller). A lot of MVC examples state that the view is decoupled from everything else and fed data by the controller. This is entirely inaccruate (see: Model-View-Confusion part 1: The View gets its own data from the Model for a detailed explanation). In MVC the vews queries the model to request its own data.

The View is not (common mistakes made by those misinterpreting the pattern):

  • Absent of logic
  • Given data by the controller

The Controller

The controller takes user input and updates the model where required. Where there is no user interaction (e.g. where a static data set is displayed and will be the same every time), no controller should be necessary. It is important to note that the controller is not a mediator or gateway between the view and the model. The view gets its own data from its model. The controller accesses the model but does not contain any display logic itself. All the controller does is respond to user input.

Each controller is linked to a single instance of a view and a single instance of a model.

The Controller is not (common mistakes made by those misinterpreting the pattern):

  • A gateway/mediator between the model and the view
  • The place where views get initialised based on the state of a model. The controller is linked to a single view class (although it could be assigned to multiple instances) and responds to actions on it. For example a list of products would be a single view. The controller would handle user actions such as sorting the list, filtering the records it's displaying based on criteria specified by users. It would not also deal with displaying the info for a single product. This is a different view, which requires its own controller.

Program flow

The typical program flow in MVC is:

  • The model, view and controller are initialised
  • The view is displayed to the user, reading data from the model
  • The user interacts with the view (e.g. presses a button) which calls a specified controller action
  • The controller updates the model in some way
  • The view is refreshed (fetching the updated data from the model)

Hello World

In standard MVC, the view would be initiated, assigned a controller and model, then rendered (Burbeck, 1992; Krasner & Pope; 1988). The user would interact with the view and this would trigger actions on the controller.

A hello world application would look something like this:

PHP Code:

class Model {
    public 
$text;
    
    public function 
__construct() {
        
$this->text 'Hello world!';
    }        
}


class 
View {
    private 
$model;
    private 
$controller;
    
    public function 
__construct(Controller $controllerModel $model) {
        
$this->controller $controller;
        
$this->model $model;
    }
    
    public function 
output() {
        return 
'<h1>' $this->model->text .'</h1>';
    }
    
}

class 
Controller {
    private 
$model;

    public function 
__construct(Model $model) {
        
$this->model $model;
    }
}



//initiate the triad
$model = new Model();
//It is important that the controller and the view share the model
$controller = new Controller($model);
$view = new View($controller$model);
echo 
$view->output();

Notice how the controller isn't doing anything? This is because there is no user interaction. Hello world is purely display.

N.b. the controller is passed to the view because in a desktop application, the view would need to create a callback on the correct controller, so it would need to know which controller was in use. This still happens on the web, but it a more subtle way. In Part 2 I'll show how this is worked around on the web.

In a lot of (so called) MVC examples and frameworks, the controller acts as an entry point that creates its view and model. I'll explain why this is later on, but it's important to understand that this is not something defined by the pattern itself and using it as an entry point can imply the usage of "fat controllers" (Brady, 2009) whereby the controller is acting as a gateway between the view and model. See my article Model-View-Confusion part 1: Why the model is accessed by the view in MVC for more information on why this is not good practice.

In this case, the traditional approach works as intended on the web. However, when user actions need to be defined, a problem occurs that forces us as PHP developers to deviate from this standard approach.

User interaction

This wouldn't be a complete example if one of the components (in this case the controller) wasn't doing anything. So let's add some user interaction so that the controller has something to do.

User interaction is the first problem with the MVC architecture on the web. There's no way to create a callback to the controller directly. The whole page needs to be reloaded. Still, not a huge issue but there needs to be some code to route the action back to the (correct!) controller.

As a simple example I will extend the Hello World example and make it so that when "Hello world" is clicked, the text will be changed to "Text updated".

Firstly, add a link to the view. This can be likened to adding a callback to the controller from the view. In GUI applications, the controller would just be another object in memory and the callback would be a simple function call. This is not an option on the web the only way to access the controller is another HTTP request.

PHP Code:

class View {
    private 
$model;
    private 
$controller;
    
    public function 
__construct(Controller $controllerModel $model) {
        
$this->controller $controller;
        
$this->model $model;
    }
    
    public function 
output() {
        return 
'<a href="mvc.php?action=textclicked">' $this->model->text '</a>';
    }
}

On the callback (second request) all the components must be re-initialised. Some code must be added to route the action back to the controller:

PHP Code:

$model = new Model();
//It is important that the controller and the view share the model
$controller = new Controller($model);
$view = new View($controller$model);
if (isset(
$_GET['action'])) $controller->{$_GET['action']}();
echo 
$view->output();

All this does is call the relevant controller action (specified by $_GET['action']) based on the user interaction.

Finally, a controller action to handle the event has to be added:

PHP Code:

class Controller {
    private 
$model;

    public function 
__construct(Model $model) {
        
$this->model $model;
    }

    public function 
textClicked() {
        
$this->model->text 'Text Updated';
    }
}

Now, when the page is visited it will say "Hello World" when the link is clicked it will say "Text updated". Not exactly rocket science but it's a basic working example of pure MVC in php.

Click here to see it working or click here to see the full source code.

Is that it?

Yes. There you have a simple bare bones example of MVC, albeit with some slight modifications to deal with the underlying technology (the web). However, deploying this pattern on the web presents some other significant technical challenges which I will address in part 2.

It is important to understand the basics of the pattern to be able to appreciate or even see the design decisions and concessions which have to be made to make it work correctly on the chosen platform. A lot of MVC tutorials skip this step and tend to throw you in at the deep end and include implementations of platform specific design decisions without explaining what is done because it's specified by the pattern and what has been done to work around limitations of the underlying technology, all the while usually only presenting how and not why.

I've tried to keep a clear distinction. In part two I'll expand on this and show other problems introduced by deploying the MVC architecture on the web. And in part three I will show you how to create a fully functional router from scratch.

Continue to part 2: Deploying MVC on the web

References

Brady, P (2009) Zend Framework: Surviving the deep end (http://www.survivethedeepend.com/zendframeworkbook/en/1.0/
the.model#zfbook.the.model.the.fat.stupid.ugly.controller
)

Burbeck, S (1992) Applications Programming in Smalltalk-80(TM): How to use Model-View-Controller (MVC) (http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html)

Deacon, J (2000) Model-View-Controller (MVC) Architecture (http://www.jdl.co.uk/briefings/MVC.pdf)

Krasner & Pope (1988) A Description of the Model-View-Controller User Interface Paradigm in the Smalltalk-80 System (http://www.itu.dk/courses/VOP/E2005/VOP2005E/8_mvc_krasner_and_pope.pdf)

Sun Microsystems (2000) Java Blueprints Model View Controller (http://java.sun.com/blueprints/patterns/MVC-detailed.html)

me

Tom Butler

27 year old Web Developer, Ph.D student and part time University Lecturer based in Milton Keynes, UK. Interests: Programming, best practices, PC Gaming, live music, gradually improving at Flying Trapeze.