Adventure,PHP,framework,page controller,front controller,pattern,object orientated design,software,development,reusability,uml,tutorial,benchmark,brilliant performance,

Search:    
Downloads  |  SVN!  |  Roadmap  |  Forum!  |  Bugtracking  |  Guestbook  |  Backlinks!  |  References!  |  Sitemap  |  Impress  
 
Deutsch | English Adventure PHP Framework  Bookmark @ Technorati Bookmark @ del.icio.us Bookmark @ Mr. Wong Bookmark @ Simpy Bookmark @ Google Bookmark @ Digg.com Adventure PHP Framework Print page 056-Frontcontroller-tutorial

Front controller tutorial

Rank article:
This article has not yet been ranked. Vote this article first of all!

1. Introduction

The implementation of the front controller of the adventure php framework can be used in several scopes due to it's timing model. The following activity diagram shows you, which actions are executed after the method start() is called:

Frontcontroller timing model

The current tutorial wants to describe the different application areas and is intended to give some hints concerning the implementation of front controller actions. A typical domain of front controller actions is the delivery of dynamic images and the validation of login credentials that are necessary for building an application model. The following chapters describe these cases and show some example code.


2. Delivery of images

Due to the fact, that the framework is designed to run in bootstrap mode, all content is delivered with one single file. The more modules an application consists of, the greater is the desire to deliver also popup windows's content or media files with this mechanism. Merely, the popup windows contain print views or forms or media files like PDF or ZIP files.

To achieve this goal, another bootstrap file can be created, that handles the different kind of requests. Unfortunately, this procedure generates code redundancy.

With aid of the front controller, exacting front controller actions, the problem of redundant code can be solved clearly. The timing model of the front controller's dispatching process (see diagram in chapter 1) allows you to execute a front controller action before the page controller page is created (see front controller documentation for details on the timing model). Thereby, the developer can decide himself, whether the requested page (including the front controller action call) is displayed within the current browser window or in a now one. Another advantage is, that the program code responsible for the additional content can be delivered directly with the modul package. This does not only lead to a better code quality but also the delivery is made easier. Further, within an front controller action a page controller page can be created and displayed.

As described in the front controller documentation, a front controller action is described by a section in the action configuration file. The configuration includes the definition of the location and name of the action and input class implementation. The complexity of the input class depends on the amount of the application's code or the tasks to be done. The socialbookmark module, that is delivered with each release, contains a action, that is intended do deliver the bookmark provider symbols. This action is now described in detail.


2.1. Action configuration

The file DEFAULT_actionconfig.ini in the /apps/config/modules/socialbookmark/action/sites/demosite folder (please refere to the current adventure-demopack-* release file) defines the action's parameters. The FC.InputParams attribute defines the default values of the input object. The configuration file looks as follows:
[showImage]
FC.ActionNamespace = "modules::socialbookmark::biz::actions"
FC.ActionFile = "ShowImageAction"
FC.ActionClass = "ShowImageAction"
FC.InputFile = "ShowImageInput"
FC.InputClass = "ShowImageInput"
FC.InputParams = "img:bookmark_del_icio_us|imgext:png"

2.2. Action implementation

The file ShowImageAction.php (see ActionFile) contains the program code of the action. In case of the image delivery, tha path to the desired image is build up and afterwards the image itself is delivered to the browser. To stop execution of further actions or the creation of the front controller page, the action contains an exit() at the end of the run() method. If the exit() is not present, the defined page controller page will be delivered. This causes the browser to display a broken image. The complete source code of the image delivery action is printed in the following code box:
   class ShowImageAction extends AbstractFrontcontrollerAction
   
{

      function 
ShowImageAction(){
      }

      function 
run(){

         
// get image from the action's input object
         
$Image APPS__PATH.'/modules/socialbookmark/pres/image/';
         
$Image .= $this->__Input->getAttribute('img').'.'.$this->__Input->getAttribute('imgext');

         
// send an image header
         
header('Content-type: image/'.$this->__Input->getAttribute('imgext'));
         
header('Cache-Control: public');

         
// stram the image file
         
readfile($Image);

         
// terminate execution
         
exit();

       
// end function
      
}

    
// end class
   

2.3. Input definition

The ShowImageInput.php file contains the input object definition, that holds the parameters applied to the action call. In case of the image delivery, no further parameters must be defined. The following class definition completes the action definition:
   class ShowImageInput extends FrontcontrollerInput
   
{

      function 
ShowImageInput(){
      }

    
// end class
   

2.4. Practice

Within the socialbookmark module, bookmark service symbols are included by the following image tag:
  <img src="/~/modules_socialbookmark-action/showImage/imgext/png/img/bookmark_technorati" alt="" />
If you analyze the url requested, the parameters involved in the front controller action call have the following meaning:
  • modules_socialbookmark: This is the namespace under which the front controller can find the action definition (see section 1.1). Due to the fact, that action configurations are context dependent, the action definition file is there expected to be stored in the folder
    {NAMESPACE}/actions/{CONTEXT}
  • -action: This suffix is attended to indicate the action call within the url.
  • showImage: Name of the action and name of the configuration section at the same time.
  • imgext: Parameter imgext
  • png: Value of the parameter imgext
  • img: Parameter img
  • bookmark_technorati: Value of the parameter img

3. Validation of login credentials

As a rule, front controller actions are used to create and fill a application model - a model represents the status of an application - before the presentation layer is created. For this task, the action can revert to it's input object, that is procured by the front controller. If desired, the action definition can already define default values for certain input parameters. These parameters are then default values during action execution.

The main challenge of the "login check action" is to validate login information included in the request, a session or a cookie and to provide this information to the application. This information is then used by the business and presenation layer to control the application and to build the GUI. Front controller actions are defined to be business layer members.

The scenario described in the last break contains two main "business cases": login information are included in the request and second, login information must be gathered from other sources like sessions or cookies. To provide the ability to login via cookies, the action must be executed with each request. For these purposes, the action handling the login functionality can be registered to the front controller as a "permanent" action. To do so, the bootstrap file must be changed like this:
   $fC = &Singleton::getInstance('Frontcontroller');
   
$fC->set('Context','my::context');
   
$fC->registerAction('my::namespace','myAction'); 
The implemenation of the action contains of three components as well. When dealing with MVC, front controller and three tier based applications, it is advisable for us to define a central application model class, that holds the current status of the application. This object can be used for flow control or business layer functionality and to build the GUI, later on.

For this example, the class described in the following code box is intendet to be the application model. To make the example not too complex, the model defines only few attributes:
   class ApplicationModel extends coreObject
   
{

      function 
ApplicationModel(){

         
// defines the view that should be displayed (login|welcome)
         
$this->__Attributes['view.content.template'] = 'login';

         
// user id of the logged in user (null|user_id)
         
$this->__Attributes['user.id'] = null;

         
// defines, how the user was logged in (request|cookie|session)
         
$this->__Attributes['login.mode'] = 'request';

         
// indicates if a login has failed
         
$this->__Attributes['login.status'] = null;

       
// end function
      
}

    
// end class
   
As you can see, the model uses the private member variable $__Attributes to store the information. That brings the advantage, that the model attributes can be used in the <fcon:importdesign /> tag to influence the GUI structure. Details on the tag can be read about in the standard taglibs chapter, section 5. Front controller.


3.1. Action configuration

To be able to call the action via request or execute it as a permanent action it must have a configuration file. The section shown in the following code box can be used as a template:
[Login]
FC.ActionNamespace = "my::module::biz::actions::login"
FC.ActionFile = "LoginAction"
FC.ActionClass = "LoginAction"
FC.InputFile = "LoginInput"
FC.InputClass = "LoginInput"
FC.InputParams = ""

3.2. Action implementation

The core functionality of an action is defined in the run() method. The following source code can be used to fullfill the functionality described above:
      function run(){

         
// register "normal" request variables
         
$_LOCALS variablenHandler::registerLocal(array('Username','Password','ID'));


         
// instanciate the application model
         
$Model = &$this->__getServiceObject('my::namespace','ApplicationModel');


         
// create the sessionManager
         
$Session = new sessionManager('MyApplication');


         
// case 1: (no direct user interaction)
         //
         //   a) data from session are not null and are valid.
         //   b) data are not included in the session.
         //
         
if(!isset($_REQUEST['Login'])){

            
// case 1.1: extract data from session
            
$Username $Session->loadSessionData('Username');
            
$Password $Session->loadSessionData('Password');

            if(!empty(
$Username) && !empty($Password)){

               if(
$this->__validateCredentials($Username,$Password)){

                  
// case 1.1.1: data from session is valid, user is logged in
                  
$Model->setAttribute('view.content.template','content');

                
// end if
               
}
               else{

                  
// case 1.1.2: data from session are not valid
                  
$Model->setAttribute('view.content.template','login');

                
// end if
               
}

             
// end if
            
}
            else{

               
// case 1.2: no data avalilable in session
               
$Model->setAttribute('view.content.template','login');

             
// end else
            
}

          
// end if
         
}
         else{

            if(
myValidator::validateText($_LOCALS['Username']) && myValidator::validateText($_LOCALS['Password'])){

               
// case 2.1: login form was sent
               
if($this->__validateCredentials($_LOCALS['Username'],md5($_LOCALS['Password']))){

                  
// case 2.1.1. login credentials are valid -> user is logged in
                  
$Model->setAttribute('view.content.template','content');

                
// end if
               
}
               else{

                  
// case 2.1.2: login request failed due to wrong username and/or password
                  
$Model->setAttribute('view.content.template','login');
                  
$Model->setAttribute('login.status','failed');

                
// end else
               
}

             
// end if
            
}
            else{

               
// case cases 2.2: form was submitted partial
               
$Model->setAttribute('view.content.template','login');

             
// end else
            
}

          
// end if
         
}


         
// case 3: logout
         //
         
if($this->__Input->getAttribute('action') == 'logout'){

            
// destroy session data
            
$Session->destroySession('MyApplication');

            
// unset user data in the locally used array
            
$_LOCALS['Username'] = '';
            
$_LOCALS['Password'] = '';
            
$_LOCALS['ID'] = '';

            
// set view to "login"
            
$Model->setAttribute('view.content.template','login');

          
// end if
         
}

       
// end function
      
The code printed above uses the framework components sessionManager, variablenHandler and myValidator. Of corse, these libraries must be included via
   import('my::namespace','ApplicationModel');
   
import('core::session','sessionManager');
   
import('tools::variablen','variablenHandler');
   
import('tools::validator','myValidator'); 
before use. This private method __validateCredentials() encapsulates the validation of the login credentials, that must be implemented by the business component.

In order to hold the model information within the entire session, the model can be instanciated in SESSIONSINGLETON mode. This opens the possibility, to have the action only executed at login or logout, because the login information is already available in the session. To mime this behavior, the model must be created as follows:
   $Model = &$this->__getServiceObject('my::namespace','ApplicationModel','SESSIONSINGLETON'); 

3.3. Input definition

In this, case no further parameter definitions must be included in the input object. The input class implemenation can thus be an empty class, that inherits from FrontcontrollerInput (see 2.3.).


Comments

Do you want to add a comment to the article above, or do you want to post additional hints? So please click here. Comments already posted can be found below.


There are no comments belonging to this article.


Powered by WebRing.