4. Building Controller Components
4.1 Overview
Now that we understand how to construct the Model and View components of your application, it is time to
focus on the Controller components. Phrame includes a controller that implements the primary function of
mapping a request URI to an Action class. Therefore, your primary responsibilities related to the Controller
are:
- Write an Action class for each logical request that may be received (extend Action).
- Configure a ActionMapping for each logical request that may be submitted. The configuration file is
usually named mapping.php.
4.2 Action Classes
The goal of an Action class is to process a request, via its perform() method, and return an ActionForward
object that identifies where control should be forwarded (e.g. a page) to provide the appropriate response.
In the MVC/Model2 design pattern, a typical Action class will often implement logic like the following in its
perform() method:
- Validate the current state of the user's session (for example, checking that the user has successfully
logged on). If the Action class finds that no logon exists, the request can be forwarded to the page that
displays the username and password prompts for logging on. This could occur because a user tried to enter
an application "in the middle" (say, from a bookmark), or because the session has timed out, and the web server
created a new one.
- If validation is not complete, validate the form properties as needed. If a problem is found, trigger the
appropriate error message, and forward control back to the input form so that the errors can be corrected.
- Perform the processing required to deal with this request (such as saving a row into a database). This can
be done by logic code embedded within the Action class itself, but should generally be performed by calling an
appropriate method of a business logic object.
- Update the server-side objects that will be used to create the next page of the user interface.
- Return an appropriate ActionForward object that identifies the page to be used to generate this response,
based on the newly updated objects. Typically, you will acquire a reference to such an object by calling get()
on either the ActionMapping object you received (if you are using a logical name local to this mapping).
Design issues to remember when coding Action classes include the following:
- The controller creates only one instance of your Action class, and uses it for all requests.
- The objects that represent the Model of your system may trigger errors due to problems accessing databases
or other resources. You should trap all such errors in the logic of your error handler, and log them (along with
the corresponding context) by calling: error_log('Error message text');
In addition, you will want to guard against Action classes that are too large. The easiest way for this to happen is
to embed your functional logic in the Action class itself, rather than coding it in separate business logic beans.
Besides making the Action class itself hard to understand and maintain, this approach also makes it harder to re-use
the business logic code, because it is embedded inside a component (the Action class) that is tied to being executed
in a web application environment.
An Action can be factored into several local methods, so long as all properties needed are passed in the method.
4.3 The Action Mappings Configuration File
How does the controller learn about the mappings you want? It would be possible (but tedious) to write a small PHP
class that simply instantiated new ActionMapping instances, and called all of the appropriate setter methods. To make
this process easier, Phrame is capable of reading an PHP-based associative array describing the desired mappings,
creating the appropriate objects along the way. The format is an associative array (instead of XML, for example) so the
overhead of parsing is kept to a minimum. The associative array can be used directly by Phrame and is easier to
manipulate at runtime.
The developer's responsibility is to create a PHP file (named mapping.php for example) and place it in the directory of
your application (the include directory for example).
The elements required in the mappings file are PHP constants (see the Constants file).
There are two important elements that are used to describe your actions:
_ACTION_FORMS
This section contains your form object definitions. Each form object has a unique identifier, which will be used to
reference it in corresponding action mappings, and has the following important attributes:
- _TYPE: The fully-qualified PHP classname of your form object.
_ACTION_MAPPINGS
This section contains your action definitions. Each action element has a unique identifier and requires the following
attributes to be defined:
- _TYPE: The fully qualified PHP classname of your Action class.
- _NAME: The name of your _ACTION_FORMS element to use with this action.
- _INPUT: Context-relative path of the input form to which control should be returned if a validation error is
encountered.
- _VALIDATE: Set to true if the validate() method of the form object (if any) associated with this mapping should
be called.
_ACTION_FORWARDS
This section contains your forward object definitions. Each action element contains forward objects that have a unique
identifier and require the following attributes to be defined:
- _PATH: Context-relative URI to which control should be forwarded, or an absolute or relative URI to which control
should be redirected.
- _REDIRECT: Set to true if the controller should redirect instead of forward on the associated path.
The mappings file from the example application "hello" includes the following mapping entry for the "say hello" function,
which we will use to illustrate the requirements.
<?php //build mapping information to pass into controller $mappings = array( _ACTION_FORMS => array( 'form' => array( _TYPE => 'HelloForm' ) ), _ACTION_MAPPINGS => array( 'sayHello' => array( _TYPE => 'HelloAction', _NAME => 'form', _INPUT => 'index.php?view=views/index.xsl', _VALIDATE => 1, _ACTION_FORWARDS => array( 'hello' => array( _PATH => 'index.php?view=views/hello.xsl', _REDIRECT => 0 ), 'index' => array( _PATH => 'index.php?view=views/index.xsl', _REDIRECT => 0 ) ) ) ) ); ?>
First the form object is defined. A basic object of class "HelloForm" is mapped to the logical name "form". Each mapping
entry contains local objects of class "ActionForward" which contain the possible states the application can forward to.
The Action classes in the example application are almost totally independent of the actual names of the pages that are used
by the page designers. The pages can be renamed (for example) during a redesign, with negligible impact on the Action
classes themselves. If the names of the "next" pages were hard coded into the Action classes, all of these classes would
also need to be modified. Of course, you can define whatever local forward properties makes sense for your own application.
4.4 The Action Controller Options File
The controller requires the appropriate initialization parameters:
- _CACHE: Set to true to enable internal "lazy" object caching
- _ERROR_REPORTING: This is a PHP directive that is a bitmask, or named constant. Using named constants is strongly
encouraged to ensure compatibility for future versions. As error levels are added, the range of integers increases, so
older integer-based error levels will not always behave as expected (see the
PHP Manual).
- _ERROR_HANDLER: This is used for defining your own way of handling errors during runtime, for example in applications
in which you need to do cleanup of data/files when a critical error happens, or when you need to trigger an error under
certain conditions using trigger_error() (see the
PHP Manual).
<?php //set options for the controller $options = array( //set to true for data caching _CACHE => 1, //set to E_ALL to get controller errors (debug use only) _ERROR_REPORTING => E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE, //sets to the function that you specify for handling errors _ERROR_HANDLER => "handleError", ); ?>
Next: User's Guide
|