Quicknavi |
|
Front controller tutorial
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:
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:
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.
|