2. Building Model Components
2.1 Overview
Many requirements documents used for building web applications focus on the View. However, you should ensure that the
processing required for each submitted request is also clearly defined from the Model's perspective. In general, the
developer of the Model components will be focusing on the creation of classes that support all of the functional
requirements. The precise nature of the beans required by a particular application will vary widely depending on those
requirements, but they can generally be classified into several categories discussed below. However, a brief review of
the concept of "scope" as it relates to models and views is useful first.
2.2 ActionForm Objects
Note: While ActionForm objects often have properties that correspond to properties in your Model objects, the form objects
themselves should be considered a Controller component. As such, they are able to transfer data between the Model and View
layers.
The Phrame framework generally assumes that you have defined an ActionForm object (that is, a PHP class extending the
ActionForm class) for the input forms in your application. ActionForm objects are sometimes just called "form objects".
These may be finely-grained objects, so that there is one object for each form, or coarsely-grained so that one object
serves several forms, or even an entire application.
If you declare such objects in your Phrame configuration file (see "Building the Controller Components"), the Phrame
controller will automatically perform the following services for you, before invoking the appropriate Action method:
- Check in the user's session for an instance of a form of the appropriate class, under the appropriate key.
- If there is no such session form available, a new one is automatically created and added to the user's session.
- For every request parameter whose name corresponds to the name of a property in the form, the corresponding setter
method will be called.
- The updated ActionForm object will be passed to the perform method of an Action class, so that the values can be
made available to your system state and business logic models.
For more about coding Actions and ActionForm objects, see the "Building Controller Components" chapter.
You should note that a "form", in the sense discussed here, does not necessarily correspond to a single page in the user
interface. It is common in many applications to have a "form" (from the user's perspective) that extends over multiple
pages. Think, for example, of the wizard style user interface that is commonly used when installing new applications.
Phrame encourages you to define a single ActionForm bean that contains properties for all of the fields, no matter which
page the field is actually displayed on. Likewise, the various pages of the same form should all be submitted to the same
Action Class. If you follow these suggestions, the page designers can rearrange the fields among the various pages, often
without requiring changes to the processing logic.
Smaller applications may only need a single ActionForm to service all of its input forms. Others applications might use a
single ActionForm for each major subsystem of the application. Some teams might prefer to have a separate ActionForm class
for each distinct input form or workflow. How many or how few ActionForms to use is entirely up to you. The framework
doesn't care.
2.3 System State Models
The actual state of a system is normally represented as a set of one or more object classes, whose properties define the
current state. A shopping cart system, for example, will include an object that represents the cart being maintained for
each individual shopper, and will (among other things) include the set of items that the shopper has currently selected
for purchase. Separately, the system will also include different objects for the user's profile information (including
their credit card and ship-to addresses), as well as the catalog of available items and their current inventory levels.
For small scale systems, or for state information that need not be kept for a long period of time, a set of system state
objects may contain all the knowledge that the system ever has of these particular details. Or, as is often the case, the
system state objects will represent information that is stored permanently in some external database (such as a
Customer object that corresponds to a particular row in the CUSTOMERS table), and are created or removed from the server's
memory as needed.
2.4 Business Logic Models
You should encapsulate the functional logic of your application as method calls in objects designed for this purpose.
These methods may be part of the same classes used for the system state objects, or they may be in separate classes
dedicated to performing the logic. In the latter case, you will usually need to pass the system state objects to be
manipulated to these methods as arguments.
For maximum code re-use, business logic objects should be designed and implemented so that they do not know they are
being executed in a web application environment. If you find yourself having to use sessions in your object, you are tying
this business logic to the web application environment. Consider rearranging things so that your Action classes (part of
the Controller role, as described below) translate all required information from the HTTP request being processed into
property setter calls on your business logic objects, after which a call to an perform() method can be made. Such a business
logic class can be reused in environments other than the web application for which they were initially constructed.
Depending on the complexity and scope of your application, business logic objects might be ordinary classes that interact
with system state objects passed as arguments, or ordinary objects that access a database. For larger applications, these
objects will often be stateful or stateless.
2.5 Accessing Relational Databases
After the database is defined, here is an example of establishing a connection (using ADODB) from within a Action perform
method.
<?php class GetDatabaseConnection extends Action { function perform($actionMapping, $actionForm) { //get information required to create connection $driver = $actionForm->get('driver'); $username = $actionForm->get('username'); $password = $actionForm->get('password'); $database = $actionForm->get('database'); //create database connection $db = &ADONewConnection($driver); $db->PConnect(false, $username, $password, $database); //use connection and then forward to next state return $actionMapping->get('mainMenu'); } }
Note that the Phrame should utilize connection pools for better performance, especially with high-volume production systems.
Next: Building View Components
|