Quicknavi |
|
Frontcontroller
1. Introduction
The front controller is as mentioned before another central integral part of the adventure php
framework. Basic to this implementation ar the definition of the fron controller pattern of
Martin Fowler
and the java sources of the java application framework
struts.
To go further into this topic please visit the
PHP patterns
website (german).
The front controller component used in this application framework is a singleton instance of the
FrontController class, takes the command given in the users' requests and executes
the actions existing for the effective application. There are several kinds of actions that are
executed according to the timing model described later on. In common, action types containing the
"pre" keyword are execuded before a specific task, action types that contain the "post" keyword are
execued after a defined step. The "prepagecreate" actions often are taken to create the application's
model, "posttransform" actions merely are used to to things like logging. To implement front controller
actions the framework contains two abstract implementations that serve as basis for concrete
implementations for actions (AbstractFrontcontrollerAction) and their information
(FrontcontrollerInput). The frontcontrollerRequestFilter and
frontcontrollerRewriteRequestFilter are designed to extract the action commands out
of the url so that the front controller can execute them. These two components the developers does
not get in contact with in common, becaus the front controller executes them itself. In order to have
actions, that are executed at each request, the developer can register these actions to the front
controller in the central index.php file. These act like normal actions concering the timing
model. The following UML diagramm shows the front controller components altogether:
2. Implementation
Software written in front controller style merely contain two areas. For a start action and input
classes must be written that inherit from AbstractFrontcontrollerAction and
FrontcontrollerInput, further, a configuration that describes the action must be
built.
2.1. Action and input classes
Classes that are descended from the abstract action and input classes encapsulate the functionality
of an action. As it is described in the API documentation
an action class must implement the run() method, because this function is execuded
for each action during dispatching. An input class is a data class that contains the model information
of the action. In a simple application, the input object of an front controller action can form the
model concurrently. The code example printed after this passage shows two simple action an input
classes:
class DemoAction extends AbstractFrontcontrollerAction {
function DemoAction(){ }
function run(){ echo 'I am front controller action class! My name is '.$this->__Input->getAttribute('Name').'!'; // end function }
// end class }
class DemoInput extends FrontcontrollerInput {
function DemoInput(){ $this->__Attributes['Name'] = 'James Blunt'; // end function }
// end class }
If this action is executed, the output shows the sentence
I am front controller action class! My name is James Blunt!
Due to the fact that actions know the context of the entire application, actions can be used to
encapsulate various parts of an application if reasonable. A popular example is user authentication.
This can be achieved by checking the user's credentials in a "prepagecreate" action and set the
parameters of the application to the desired valued.
2.2. Configuration
Each action must be defined within a configuration file. This file must contain the namespace to the
action and input classes, the file name of the classes and the class names itself. Configuration
files must be stored under the directory that can be defined by the expression
{ActionNamespace}::actions::{Context}
The name of the configuration file can be described by
{ENVIRONMENT}_actionconfig.ini
{ENVIRONMENT} must be replaced by the current value of the environment variable stored
in the registry. By default, this valus must be replaced with DEFAULT. Each file can
contain one or more action definitions for actions, that belong to the same namespace.
[{ActionName}]
FC.ActionNamespace = ""
FC.ActionFile = ""
FC.ActionClass = ""
FC.InputFile = ""
FC.InputClass = ""
FC.InputParams = ""
Besides, the performed parameters have the following meanings:
-
ActionName:
Name of the action. This name must be present in the URL if the defined action should be called
(Example: setModel).
-
FC.ActionNamespace:
Namespace of the action's configuration file (Example: sites::demosite::biz::actions).
-
FC.ActionFile:
Name of the file that contains the action class implementation (Example: LoadModelAction).
-
FC.ActionClass:
Name of the action class (Example: LoadModelAction).
-
FC.InputFile:
Name of the file, the input class resides (Example: DemositeModel).
-
FC.InputClass:
Name of the input class (Example: DemositeModel).
-
FC.InputParams:
Configuration directive that defines the start parameters of an input object. This is often used
to configure a specific action for the use in a specific application without changing the source
code. (Example: login:true|headview:menu. Key and value are separated by ":", different
pairs by "|").
Due to the fact, that front controller actions are part of the business layer the code files should
be placed under the biz folder of an module or application. In common the developer
creates a subfolder named actions to store these files and to generate more clarity.
Since namespace and name of the class files can be choosen freely the developer faces no restictions.
2.3. Changes to the index.php
To operate an application in front controller style the index.php file must contain the
following lines of code:
// create an instance of the front controller $fC = &Singleton::getInstance('Frontcontroller');
// set the context of the application $fC->set('Context','sites::demosite');
// set the desired standard language $fC->set('Language','de');
// generate the specified site $fC->start('sites::demosite::pres::templates','website');
If desired the developer can register "permanent" actions by
// register action "Login" $fC->registerAction('sites::demosite::biz','Login');
before the execution of the start() methode. Now it is possible to execute any
actions in applications or modules.
2.4. Link generation
In order to generate links as easy as within page controller applications the component
frontcontrollerLinkHandler was introduced. This class can be used to manipulate
existing URLs or create new URLs. If an action's private attribute $__KeepInURL is
set to true, the action along with its input attributes is added to the URL that is
generated by the frontcontrollerLinkHandler. This adds the possibility to have more
than one action definition in one URL and so create complex programms. The following example shows
how the frontcontrollerLinkHandler can be used. To keep things simple the links will
be descussed in rewrite mode only. Manipulating "normal" URLs is similar.
2.4.1. Simple manipulation of parameters
In many applications it is necessary to generate dynamic links. Within front controller based
applications where no dynamic URLs are necessary the linkHandler can be used instead
of the frontcontrollerLinkHandler component. But it is recommended to use the the
latter to be secure. To change the link
http://www.adventure-php-framework.org/Page/Home/benchmarkreport/true/param1/value1/param2/value2
to the link
http://www.adventure-php-framework.org/Page/Guestbook/benchmarkreport/true
in an easy way, the following code fragment can be used:
// define URL $URL = 'http://www.adventure-php-framework.org/Page/ChangeLog/benchmarkreport/true/param1/value1/param2/value2';
// define changes $ChangeParams = array( 'Page' => 'Guestbook', 'param1' => '', 'param2' => '' );
echo frontcontrollerLinkHandler::generateLink($URL,$ChangeParams);
2.4.2. Manipulation of parameters and actions
Action definitions are treated as "normal" URL parameters as well. Thus is low-end to change the URL
http://www.adventure-php-framework.org/Page/ChangeLog/benchmarkreport/true/param1/value1/param2/value2
to
http://www.adventure-php-framework.org/Page/Guestbook/benchmarkreport/true/param1/value1/param2/value2/~/
modules_guestbook_biz-action/LoadEntryList/pagesize/20/pager/false/adminview/true
In this case the following parameter array was given to the generateLink methode:
// define URL $URL = 'http://www.adventure-php-framework.org/Page/ChangeLog/benchmarkreport/true/param1/value1/param2/value2';
// define changes to the URL $ChangeParams = array( 'modules_guestbook_biz-action:LoadEntryList' => 'pagesize:20|pager:false|adminview:true', 'Page' => 'Guestbook' );
// generate link echo frontcontrollerLinkHandler::generateLink($URL,$ChangeParams);
If the desired action was added as a "permanent" action it is only necessary to call the
frontcontrollerLinkHandler without a second parameter. In doing so all actions that
have configured $__KeepInURL to true will be contained in the URL definition.
2.4.3. Manipulation of parameters and actions with help of generateURLParams()
The example in chapter 1.4.2 has the disadvantage, that the developer must be aware of the syntax of
a frontcontroller URL. To make generation of front controller URLs more comfortable, the
frontcontrollerLinkHandler features the method generateURLParams.
This function can generate an action parameter array for use with the generateLink() method.
Generation goes as follows:
// define URL $URL = 'http://www.adventure-php-framework.org/Page/ChangeLog/benchmarkreport/true/param1/value1/param2/value2';
// define URL changes $ChangeParams = array( 'Page' => 'Guestbook' );
// Parameter der FrontController-Action erzeugen $ChangeParams = array_merge( $ChangeParams, frontcontrollerLinkHandler::generateURLParams( 'modules::guestbook::biz', 'LoadEntryList', array( 'pagesize' => '20', 'pager' => 'false', 'adminview' => 'true' ) ) );
// generate link echo frontcontrollerLinkHandler::generateLink($URL,$ChangeParams);
Owing to performance issues this method should not be used excessively. One generation commonly
consumes about 0.004 sec to generate the parameter array. If the operation mode concerning the url
style is clear, the URLs should be generated as described in chapter 1.4.2.
2.5. Timing model
The FrontController has it's own timing model that enables the developer to influence at which point
of time the action is executed. The time can be defined the class attribute $__Type
of the AbstractFrontcontrollerAction class. This value is prepagecreate
by default. There are four modes defined:
-
prepagecreate: Action is executed before the page object is created an the DOM
tree is created.
-
postpagecreate: Action is executed after the creation of the page controller page.
-
pretransform: Action is executed before transforming the page controller page.
-
posttransform: Action is executed after transforming the page controller page.
To define the right mode of your action, please define your action class as follows:
class MyAction extends AbstractFrontcontrollerAction {
// set timing var $__Type = 'pretransform';
function MyAction(){ }
function run(){ }
// end class }
Details for the function run() can be seen in the API documentation
of the class Frontcontroller.
2.6. Model based view concept
In contrast to page controller applications, the front controller allows to instanciate the business
layer before the presentation tier. This holds the advantage to use the business
layer to control the presentation tier, in particular, the views or the content of the views of an
application.
To rip this advantage off in GUI design the XML taglib fcon_taglib_importdesign was
introduced. This component includes views, that are defined within an application model, that is filled
by front controller actions. In common the developer can create a independent business class like this:
class DemoSiteModel extends coreObject {
function DemoSiteModel(){ $this->__Attributes['view.content.template'] = 'login'; $this->__Attributes['view.topmenu.template'] = 'empty'; // end function }
// end class }
Filling the attributes can be achieved by getting reference on this class by
$Model = &$this->__getServiceObject('sites::demosite::biz','DemoSiteModel');
By adding the XML tag
<fcon:importdesign
templatenamespace="sites::apfdocupage::pres::templates"
modelnamespace="sites::demosite::biz"
modelfile="DemoSiteModel"
modelclass="DemoSiteModel"
modelparam="view.content.template"
/>
to a template file a view depending on the model's parameters can be included. To use the tag it
must be announced using the
<core:addtaglib namespace="tools::html::taglib" prefix="fcon" class="importdesign" />
directive.
With this concept views can easily be included by model information and the GUI can be controlled by
the business layer completely. Moreover this is more flexible compared with the page controller as
a single responsible entity.
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.
|