Frontcontroller
The front controller is - along with the Pagecontroller - another central integral part
of the adventure php framework. Basic to this implementation are the definition of the front
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 in the following diagram:
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 FrontControllerInputFilter is designed to extract the action commands out of
the url so that the front controller can execute them. This component the developers does not get
in contact with in common, because the front controller executes it internally 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:
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.
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:
PHP-Code
class DemoAction extends AbstractFrontcontrollerAction {
function DemoAction(){
}
function run(){
echo 'I am front controller action class! My name is '.
$this->__Input->getAttribute('Name').'!';
}
}
class DemoInput extends FrontcontrollerInput {
function DemoInput(){
$this->__Attributes['Name'] = 'James Blunt';
}
}
If this action is executed, the output shows the sentence
APF-Template
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.
Note:
Within an action it is easy to access the input object via the
$__Input
variable. If you have to access an action's input from
outside the action, you can use the
getInput() method. This function returns the action's input as a reference.
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
APF-Template
{ActionNamespace}::actions::{CONTEXT}
The name of the configuration file can be described by
APF-Template
{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.
APF-Template
[{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.
To operate an application in front controller style the
index.php file must contain the
following lines of code:
PHP-Code
// create an instance of the front controller
$fC = &Singleton::getInstance('Frontcontroller');
// set the context of the application
$fC->setContext('sites::demosite');
// set the desired standard language
$fC->setLanguage('de');
// generate the specified site
$fC->start('sites::demosite::pres::templates','website');
If desired the developer can register "permanent" actions by
PHP-Code
// 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.
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.
This behaviour is only activated, if the constructor of the desired action contains the assignment
of the value true to the $__KeepInURL class member. By default,
the value is false. If not set to true, all action instructions
are removed from the generated URL. 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.
The link schema of a front controller action instruction within the url is
APF-Template
{namespace}-action:{name}={key1}:{value1}|{key2}:{value2}|...
for normal urls and
APF-Template
/{namespace}-action/{name}/{key1}/{value1}/{key2}/{value2}/...
for rewrite urls. With normal urls,
& or
? is used as a separator
between parameters and action instructions, with rewrite urls, you have to use
/~/.
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
APF-Template
http://adventure-php-framework.org/Page/Home/benchmarkreport/true/param1/value1/param2/value2
to the link
APF-Template
http://adventure-php-framework.org/Page/Guestbook/benchmarkreport/true
in an easy way, the following code fragment can be used:
PHP-Code
// define URL
$URL = 'http://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);
Action definitions are treated as "normal" URL parameters as well. Thus is low-end to change the URL
APF-Template
http://adventure-php-framework.org/Page/ChangeLog/benchmarkreport/true/param1/value1/param2/value2
to
APF-Template
http://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:
PHP-Code
// define URL
$URL = 'http://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.
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:
PHP-Code
// define URL
$URL = 'http://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.
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:
PHP-Code
class MyAction extends AbstractFrontcontrollerAction {
// set timing
var $__Type = 'pretransform';
function MyAction(){
}
function run(){
}
}
Details for the function
run() can be seen in the
API documentation
of the class
Frontcontroller.
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:
PHP-Code
class DemoSiteModel extends APFObject {
function DemoSiteModel(){
$this->__Attributes['view.content.template'] = 'login';
$this->__Attributes['view.topmenu.template'] = 'empty';
}
}
Filling the attributes can be achieved by getting reference on this class by
PHP-Code
$Model = &$this->__getServiceObject('sites::demosite::biz','DemoSiteModel');
By adding the XML tag
APF-Template
<fcon:importdesign
templatenamespace="sites::apfdocupage::pres::templates"
modelnamespace="sites::demosite::biz"
modelfile="DemoSiteModel"
modelclass="DemoSiteModel"
modelparam="view.content.template"
[sessionsingleton="true|false"]
/>
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
APF-Template
<core:addtaglib namespace="tools::html::taglib" prefix="fcon" class="importdesign" />
directive. The
sessionsingleton attribute defines, whether the model class is created in
SESSIONSINGLETON or in
SINGLETON mode. Details on the object creation can be taken
from the
API documentation of the
ServiceManager class.
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.