Front controller tutorial
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.
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.
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:
APF-Konfiguration
[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"
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:
PHP-Code
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();
}
}
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:
PHP-Code
class ShowImageInput extends FrontcontrollerInput {
function ShowImageInput(){
}
}
Within the socialbookmark module, bookmark service symbols are included by the following image tag:
APF-Template
<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
APF-Template
{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
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:
PHP-Code
$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:
PHP-Code
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;
}
}
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.
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:
APF-Konfiguration
[Login]
FC.ActionNamespace = "my::module::biz::actions::login"
FC.ActionFile = "LoginAction"
FC.ActionClass = "LoginAction"
FC.InputFile = "LoginInput"
FC.InputClass = "LoginInput"
FC.InputParams = ""
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:
PHP-Code
function run(){
// register "normal" request variables
$_LOCALS = RequestHandler::getValues(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');
}
else{
// case 1.1.2: data from session are not valid
$Model->setAttribute('view.content.template','login');
}
}
else{
// case 1.2: no data avalilable in session
$Model->setAttribute('view.content.template','login');
}
}
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');
}
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');
}
}
else{
// case cases 2.2: form was submitted partial
$Model->setAttribute('view.content.template','login');
}
}
// 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');
}
}
The code printed above uses the framework components
SessionManager,
RequestHandler
and
myValidator.
Of corse, these libraries must be included via
PHP-Code
import('my::namespace','ApplicationModel');
import('core::session','SessionManager');
import('tools::request','RequestHandler');
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:
PHP-Code
$Model = &$this->__getServiceObject('my::namespace','ApplicationModel','SESSIONSINGLETON');
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.