Front controller

1. Introduction

The front controller is - along with the Page controller - 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 provides several entry points to influence the request processing of the framework concerning the below timing model. It is the basis to execute code and provide common information before the page is created. After page creation or transformation further code can be executed to process your application's logic.

Frontcontroller timing model

In complex web applications you often have the need to know about the pieces of the page before page creation to be able to flexibly change them concerning the user information (e.g. Login). Further implementation ideas can be taken from the model based view concept chapter. In order to execute a given action or a set of given actions at each request the developer can register these actions within the bootstrap file. In terms of the timing model, they act as "normal" actions.

The front controller component of the application framework consists of a singleton component of the Frontcontroller class. Using the appropriate input filter the request url and the request parameters are analyzed and the actions encoded in the url are executed concerning the timing model.

The APF offers two basic classes for action implementation: AbstractFrontcontrollerAction to create actions and FrontcontrollerInput to implement custom input classes.

The wiki page Unterschied Front-Controller und Page-Controller (German) details the idea of the page controller and describes the main application case.

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.

Separating implementation and configuration has the advantages that the implementation is hidden from the outside and additional dependencies can be resolved by the implementation transparently.

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 executed 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 { public function run() { echo 'I am front controller action class! My Name is '. $this->input->getAttribute('Name').'!'; } } class DemoInput extends FrontcontrollerInput { public function __construct() { $this->setAttribute('Name', 'Max Mueller'); } }

If this action is executed, the output shows the sentence

Code
I am front controller action class! My name is James Blunt!
Since release 1.14 input classes are optional. In case the logic of the input class is limited to storing the input parameters it is not necessary to implement a custom one. Here, you can instruct the front controller to use the FrontcontrollerInput class that is shipped with the APF.

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.

Within an action it is easy to access the input object via the $this->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.

2.2. Configuration

Every action must be described within a configuration file. The definition includes namespace, file name for action and input classes, the name of the classes and model information. The configuration files must be placed under the action namespace using the APF configuration schema.

In case you intent to call an action named showCaptcha having the namespace modules::captcha::biz and the name showCaptcha (url or direct registration) the front controller expects the action configuration being located in the actionconfig.ini file located in the namespace mentioned above. Given the fact, that the current APF installation is configured for context projectone and the default setting for the environment parameters the configuration file is expected under

Code
/APF/config/modules/captcha/biz/projectone/DEFAULT_actionconfig.ini

The file itself must at least contain one action definition like this:

APF configuration
[{ActionName}] FC.ActionNamespace = "" FC.ActionClass = "" [FC.InputClass = ""] FC.InputParams = ""

Besides, the listed 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.ActionClass:
    Name of the action class (Example: LoadModelAction).
  • 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 "|").
In case no custom input implementation is needed you can leave out the FC.InputClass parameter. Custom input class implementations are only necessary if it contains action parameter processing.

2.3. The bootstrap file

To enable your application to use the front controller, the bootstrap file (index.php) must at least contain the following lines:

PHP code
require('./apps/core/pagecontroller/pagecontroller.php'); import('core::frontcontroller','Frontcontroller'); $fC = &Singleton::getInstance('Frontcontroller'); $fC->setContext('sites::demosite'); $fC->setLanguage('de'); echo $fC->start('sites::demosite::pres::templates','website');
Since release 1.13 the result of the front controller execution is not printed automatically but must be sent to the client using echo. This enables you to precess the result within unit tests or things like this.

Since the front controller uses the Page controller the latter must be included before using the front controller using include() or require().

As you can take from the timing diagram in chapter 1 the input and output filters are executed during the front controller execution. The are intended to resolve the incoming request concerning the url layout and pass the action instructions to the front controller. In case of a custom url layout this fact must be taken into consideration.

Since version 1.14 input and output filters are only executed by the front controller. Thus, the Page controller can be used to generate HTML but is no more the leading component for request processing by concept.
In case your process requires actions that are executed on every request, these actions can be added before starting the front controller by adding the line
PHP code
$fC->registerAction('sites::demosite::biz','Login');
Registering an action is thereby independent of the type of the action (e.g. prepagecreate, ...).

As the design pattern teaches us, the front controller is able to execute multiple actions per requests - so it the APF front controller. As already mentioned above, actions are subjected to the timing model and can be executed at various time points.

Management of the action calls is part of the front controller implementation. In contrast, the registration is done by the the appropriate Filter or by the developer itself calling the registerAction() method.

Please note, that all information in chapter 2.4.3 up to 2.4.6 are deprecated with release 1.14. Please use the link generating facility described in chapter Links to generate action links!
2.4.1. URL layout

To allow multiple actions per request the APF defines a special url layout. This scheme includes action addresses as well as parameters. Please note, that the the length of the url is limited and so is the number of actions. The scheme is as follows:

Code
{namespace}-action:{config-name}={param1}:{value1}|{param2}:{value2}|...

Thereby, {namespace} is the namespace of the action configuration file and {config-name} is the name of the section that defines the action implementation. Param sets are separated by "|", name and value are separated by ":". As mentioned above it is possible to place multiple action calls within the url. Please see the following example that contains two action calls as well as simple parameters:

Code
?projects_projectone-action:setModel=pageid:1|lang:de&news-page=3&projects_projectone-action:stat=action:view|referer:32
Please be aware, that the order of the definition directly influences the execution order!

Using rewrite urls the scheme has been designed to distinguish between action instructions and normal parameters, too. Here, "/~/" is used as a separator. The scheme is similar to the scheme presented above:

Code
/~/{namespace}-action/{config-name}/{param1}/{value1}/{param2}/{value2}/...

"Normal" parameters are also separated from action instructions or action instruxtions from other actions with the separator noted above. The rewrite url according to the sample above is then:

Code
/~/projects_projectone-action/setModel/pageid/1/lang/de/~/news-page/3/~/projects_projectone-action/stat/action/view/referer/32
This url approach is designed for generic use. If this layout is not sufficent concerning your SEO or other requirements it can be changed using a custom input filter. You are able to generate action calls with RewriteRules as well as using an adapted input filter that decodes your url layout. A tutorial on creating a custom url layout using input filters can be found within the Wiki (German).
2.4.2. Managing actions

AbstractFrontcontrollerAction defines further mechanisms that can be used to influence action execution behaviour. Beneath the timing mode and the facility to register permanent actions, it is possible to activate and deactivate on demand. You can use this to execute an action when a specific action is on the stack or is not. Further, you are free to place your own logic.

For this reason isActive() can be overridden from AbstractFrontcontrollerAction to encapsulate your own logic:

PHP code
public function isActive() { $captcha = &$this->getParentObject()->getActionByName('showCaptcha'); return $captcha === null; }

The code placed in the above code box activates the action in case the showCaptcha is not requested - means the action is not on the stack.

This functionality can be used as of release 1.13!

2.5. Timing model

The front controller 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 (TYPE_PRE_PAGE_CREATE): Action is executed before the page object is created an the DOM tree is created.
  • postpagecreate (TYPE_POST_PAGE_CREATE): Action is executed after the creation of the page controller page.
  • pretransform (TYPE_PRE_TRANSFORM): Action is executed before transforming the page controller page.
  • posttransform (TYPE_POST_TRANSFORM): 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 at class declaration for release <= 1.13 protected $type = 'pretransform'; // set timing at class declaration for release > 1.13 protected $type = self::TYPE_PRE_PAGE_CREATE; public function __construct() { // set timing at construction for release <= 1.13 $this->type = 'pretransform' // set timing at construction for release > 1.13 $this->type = self::TYPE_PRE_PAGE_CREATE } public function run() { } }

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 create 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 FrontControllerImportTemplateTag 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 SiteModel extends APFObject { public function __construct(){ $this->setAttribute('view.content.template', 'login'); $this->setAttribute('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="SiteModel" modelclass="SiteModel" 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" class="FrontControllerImportTemplateTag" prefix="fcon" name="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 Services chapter.

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.