NewsFeaturesDownloadsDevelopmentSupportAbout Us

Model-View-Controller in LifeType

From LifeType Wiki

Contents

Model-View-Controller in LifeType

LifeType uses a slightly modified version of the Model-View-Controller pattern as its internal core structure. Explaining the MVC pattern is beyond the scope of this document so please have a look at the following documents if you are not yet familiar with it: http://www.phppatterns.com/index.php/article/articleview/11/, http://ootips.org/mvc-pattern.html, http://java.sun.com/blueprints/patterns/MVC-detailed.html

Introduction to MVC

You may agree or not with the suitability of the MVC pattern for 3-tiered web applications. There have been countless hot discussions about the topic and there will be many more in the future, but the bottom line is that this is how LifeType is built and this is not likely going to change in the future. If interested, these are the main reasons why MVC was chosen for LifeType:

  • It is a known pattern, known to work and with which LifeType developers were quite familiar.
  • It clearly separates what is content from what is logic, both at a conceptual (when we look at the system from a design point of view) level and at a technical level (when we code)
  • Using a controller, our pages become simpler and more elegant, rather than having a huge if-else branch covering all possibilities.
  • Sun recommends it in its Java Blueprints documents, and Jakarta Struts is built based on MVC (however this might hardly be a reason for some people)

The difference between LifeType's implementation and the "official" implementation is that in the official one, the controller is the one choosing the view based on the action that was executed, its result and the input. In the case of LifeType, things are a little bit easier and we simply let the current action choose its view, or how it is going to present the data. Once the action has finished processing, the controller will simply take the view chosen by the action, render it, and send the output back to the client.

Components of an MVC architecture

The Controller

In LifeTyp, the controller has been implemented using the Front Controller pattern. Users wishing to extend LifeType by adding new actions, do not have to provide their own controller. The Model layer of the MVC pattern is provided by both classes extending the Action class (these are the ones with which the controller deals) and extending the Model class, which provides database access. Since PHP does not provide multiple inheritance, we will usually need one class extending Action and one or more than one extending from Model to provide access to data. Regarding the View layer, it is provided by the View class, which is a very simple implementation of a view.

In order to implement the controller, the Front Controller pattern was chosen (references: http://java.sun.com/blueprints/corej2eepatterns/Patterns/FrontController.html, http://wact.sourceforge.net/index.php/FrontController, http://phppatterns.com/index.php/article/articleview/81/1/1/) The Front Controller provides a kind of "central hub" where all the requests are received and routed to the most suitable Model (Action, in the context of LifeType) class.

The controller has table that maps an action parameter (a parameter that comes in the request) with a class. It can also take care of dynamically loading the Action classes if needed, and provides support for easy data validation.

Being the central point where all requests go through, some operations that have to be executed at every request could be placed there. However, the implementation of a front controller is very easy and does nothing more than loading the right class and allowing action classes to validate their data before processing the request (more on this later) The class that implements a generic controller is in file *class/controller/controller.class.php*.

A very simple implementation of a script using LifeType's front controller implementation, could look like this:

  <?php
  
    include_once( "class/controller/controller.class.php" );
  
    $actionMap["Default"] = "DefaultAction";
    $actionMap["ViewArticle"] = "ViewArticleAction";
    $actionMap["AddComment"] = "AddCommentAction";
  
    $controller = new Controller( $actionMap, "op" );
  
    $controller->process( $_REQUEST );
  ?>

After including the necessary code, we define an array with the mappings. The key of the array is the string identifying the action class and the value of the action parameter in the request that the client will have to use to trigger an action, while the value in the array is the name of the action class. Action classes can be found in class/action/.

Next, we create an instance of a Controller object. The first parameter is the array with the mappings while the second one is the name action parameter that the controller will search in the request. Therefore, requests will have to look like http://.../index.php?op=ViewArticle&extraParameters. The controller will detect the "op" parameter and will use it to find the right action. If there is no action parameter in the request, or there is no action class assigned to a given parameter, the controller will execute the action identified with the key "*Default*". If it doesn't exist, it will throw an error.

If we wish to add more actions to the public side of LifeType, then we can have a look at *class/controller/controllermap.properties.php*. If we wish to add more actions to the admin interface, then the class to look at is *class/controller/admincontrollermap.properties.php*. The class/controller/blogcontroller.class.php and class/controller/admincontroller.class.php are only commodity classes that automatically load the right mappings, if interested.

Actions

In the MVC pattern, action classes encapsulate all the business logic of our application

Actions in LifeType

Once we have set up our mappings and created a Controller object, it is time to get into action (no pun intended) In order to provide some logic to our application, we have to create our own action classes by extending the Action base class (*class/action/action.class.php*). The Action class is a very simple class that has a constructor and a method called *perform()*. The perform method is the most important one because it is the one that the controller automatically calls when processing a request. *Our action class won't work and the controller will throw an error if we don't provide this method!*.

The perform() is the one that encapsulates the logic behind the action and the one that chooses a view. For example, if we had an action called ViewArticleAction, the perform() method would take care of fetching the article from the database, choosing the right view (probably, ViewArticleView) and returning control to the controller.

The Action class has the following private attributes:

  • _view: Points to the chosen view. If no view has been chosen yet, then it points to nothing.
  • _request: This is a Request object that provides methods getValue and setValue for accessing the request that came from the client. Alternatively, we can always use the $_REQUEST global array provided by PHP.
  • _actionInfo: An ActionInfo object that provides the action with information such as which was the action parameter name, its value, amongst others.

Very roughly, a simple class that fetches an article and puts it in a view (though we don't know how that works yet) would look like:

 <?php
 
   include_once( "class/action/action.class.php" );
 
   class ViewArticleAction extends Action
   {
       function ViewArticleAction( $actionInfo, $httpRequest )
       {
           $this->Action( $actionInfo, $httpRequest );
       }
 
       function perform()
       {
           $articles = new Articles();
           $article  = $articles->getArticle( $this->_request->getValue( "id" ));
 
           $this->_view = new ViewArticleView();
           $this->_view->setValue( "article", $article );
 
           return true;
       }
   }
 ?>

We will assume that the Articles class takes care of fetching articles and that its getArticle method takes exactly one parameter (the article identifier), and that it returns an object containing information about the object (even though simplified, this is how it basically works in LifeType)

Once we have what we were looking for, we can create our own view and place a first value in it (more on views later) and return a positive result to the controller.

So far, it was easy. But how about data validation? Is there an easy way to check if the data sent by the client was correct and if not, stop the whole process throwing an error...? The anwer is "Yes" :)

This could still be done by adding even more error control to the perform() method, but in combination with action classes, the controller will allow you to check for errors inside an specific function and if an error was found, it will not even execute the perform() method of the class. See Forms and data validation for more information on how to perform checks for data validation and how to deal with forms in LifeType.

Pre-defined Action classes

  • BlogAction
  • AdminAction

Views

Views take care of laying out the data and generating the right format for users. Views usually generate XHTML code in LifeType but they can potentially generate any kind of output (XML, PDF, etc)