1. Introduction

1.1 The Model-View-Controller ("MVC") Design Pattern

In the MVC design pattern, application flow is mediated by a central Controller. The Controller delegates requests - in our case, HTTP requests - to an appropriate handler. The handlers are tied to a Model, and each handler acts as an adapter between the request and the Model. The Model represents, or encapsulates, an application's business logic or state. Control is usually then forwarded back through the Controller to the appropriate View. The forwarding can be determined by consulting a set of mappings, usually loaded from a database or configuration file. This provides a loose coupling between the View and Model, which can make applications significantly easier to create and maintain.

1.1.1 The Model: System State and Business Logic PHPBeans

The Model portion of an MVC-based system can be often be divided into two major subsystems -- the internal state of the system and the actions that can be taken to change that state. In grammatical terms, we might think about state information as nouns (things) and actions as verbs (changes to the state of those things).

Many applications represent the internal state of the system as a set of one or more PHPBeans. The bean properties represent the details of the system's state. Depending on your application's complexity, these beans may be self contained (and know how to persist their own state), or they may be facades that know how to retrieve the system's state from another component. This component may be a database, a search engine, a LDAP server, or something else entirely.

Large-scale applications will often represent the set of possible business operations as methods that can be called on the bean or beans maintaining the state information. For example, you might have a shopping cart bean, stored in session scope for each current user, with properties that represent the current set of items that the user has decided to purchase. This bean might also have a checkOut() method that authorizes the user's credit card and sends the order to the warehouse to be picked and shipped. Other systems will represent the available operations separately.

In a smaller scale application, on the other hand, the available operations might be embedded within the PHRUTS_Action classes that are part of the PHruts control layer. This can be useful when the logic is very simple or where reuse of the business logic in other environments is not contemplated.

The PHruts framework architecture is flexible enough to support most any approach to accessing the Model, but we strongly recommend that you separate the business logic ("how it's done") from the role that PHRUTS_Action classes play ("what to do").

For more about adapting your application's Model to PHruts, see the Building Model Components chapter.

1.1.2 The View: PHP Pages and Presentation Components

The View portion of a PHtruts-based application is most often constructed using PHP Pages. PHP pages can contain static HTML (or XML) text called "template text", plus the ability to insert dynamic content based on the interpretation (at page request time) of PHP tags.

PHruts includes an API library that facilitate creating user interfaces that are fully internationalized, and that interact gracefully with PHRUTS_ActionForm beans that are part of the Model portion of the system.

For more about using presentation pages with the framework, see the Building View Components chapter.

1.1.3 The Controller: PHRUTS_ActionService and PHRUTS_ActionConfig

The Controller portion of the application is focused on receiving requests from the client (typically a user running a web browser), deciding what business logic function is to be performed, and then delegating responsibility for producing the next phase of the user interface to an appropriate View component. In PHruts, the primary component of the Controller is an instance of class PHRUTS_ActionService. This instance is configured by defining a set of ActionConfigs. A PHRUTS_ActionConfig defines a path that is matched against the request URI of the incoming request, and usually specifies the fully qualified class name of an Action class. All Actions are subclassed from phruts::action::PHRUTS_Action. Actions encapsulate the business logic, interpret the outcome, and ultimately dispatch control to the appropriate View component to create the response.

PHruts also supports the ability to use PHRUTS_ActionConfig classes that have additional properties beyond the standard ones required to operate the framework. This allows you to store additional information specific to your application, but still utilize the remaining features of the framework. In addition, PHruts lets you define logical "names" to which control should be forwarded so that an action method can ask for the "Main Menu" page (for example), without knowing what the actual name of the corresponding PHP page is. These features greatly assist you in separating the control logic (what to do) with the view logic (how it's rendered).

For more about the PHruts control layer, see the Building Controller Components chapter.

1.2 PHruts Control Flow

The PHruts framework provides several components that make up the Control layer of a MVC-style application. These include a controller service, developer-defined request handlers, and several supporting objects.

The PHruts API library provide direct support for the View layer of a MVC application, it access the control-layer objects. Other presentation technologies, like Smarty can also be used with PHruts.

The Model layer in a MVC application is often project-specific. PHruts is designed to makes it easy to access the business-end of your application, but leaves that part of the programming to other products.

Let's step through how this all fits together.

When initialized, the controller parses a configuration file (phruts-config.xml) and uses it to deploy other control layer objects. Together, these objects form the PHruts Configuration. The PHruts Configuration defines (among other things) the ActionConfigs [phruts::config::PHRUTS_ActionConfig] for an application.

The PHruts controller service consults the ActionConfigs as it routes HTTP requests to other components in the framework. Requests may be forwarded to PHP Pages or Action [phruts::action::PHRUTS_Action] subclasses provided by the PHruts developer. Often, a request is first forwarded to an Action and then to a PHP page (or other presentation page). The mappings help the controller turn HTTP requests into application actions.

An individual ActionConfig [phruts::action::PHRUTS_ActionConfig] will usually contain a number of properties including:

The Action object can handle the request and respond to the client (usually a Web browser) or indicate that control should be forwarded elsewhere. For example, if a login succeeds, a login action may wish to forward the request onto the mainMenu page.

Action objects have access to the application's controller service, and so have access to that service's methods. When forwarding control, an Action object can indirectly forward one or more shared objects, including PHPBeans, by placing them in one of the standard contexts shared by controller services.

For example, an Action object can create a shopping cart bean, add an item to the cart, place the bean in the session context, and then forward control to another mapping. That mapping may use a PHP Page to display the contents of the user's cart. Since each client has their own session, they will each also have their own shopping cart.

In a PHruts application, most of the business logic can be represented using PHPBeans. An Action can call the properties of a PHPBean without knowing how it actually works. This encapsulates the business logic, so that the Action can focus on error handling and where to forward control.

PHPBeans can also be used to manage input forms. A key problem in designing Web applications is retaining and validating what a user has entered between requests. With PHruts, you can define your own set of input bean classes, by subclassing ActionForm [phruts::action::PHRUTS_ActionForm]. The ActionForm class makes it easy to store and validate the data for your application's input forms. The ActionForm bean is automatically saved in one of the standard, shared context collections, so that it can be used by other objects, like an Action object or another PHP Page.

The form bean can be used by a PHP Page to collect data from the user ... by an Action object to validate the user-entered data ... and then by the PHP Page again to re-populate the form fields. In the case of validation errors, PHruts has a shared mechanism for raising and displaying error messages.

Here is the sequence of events that occur when a request calls for an mapping that uses an ActionForm:

The PHruts API library includes methods that can automatically populate fields from a PHPBean. All most PHP Pages really need to know about the rest of the framework is the field names to use and where to submit the form.

Other API methods can automatically output messages queued by an Action or ActionForm and simply need to be integrated into the page's markup. The messages are designed for localization and will render the best available message for a user's locale.

The PHruts framework and its API library were designed to support internationalization features. All the field labels and messages can be retrieved from a message resource. To provide messages for another language, simply add another file to the resource bundle.

Internationalism aside, other benefits to the message resources approach are consistent labeling between forms, and the ability to review all labels and messages from a central location.

For the simplest applications, an Action object may sometimes handle the business logic associated with a request. However, in most cases, an Action object should invoke another object, usually a PHPBean, to perform the actual business logic. This lets the Action focus on error handling and control flow, rather than business logic. To allow reuse on other platforms, business-logic PHPBeans should not refer to any Web application objects. The Action object should translate needed details from the HTTP request and pass those along to the business-logic beans as regular PHP variables.

In a database application, for example:

Neither the Action nor the PHP Page need to know (or care) from where the result comes. They just need to know how to package and display it.

Next: Building Model Components

This documentation is a modified copy of the Apache Struts 1.1 framework user guide, and so is copyrighted under the ASF license.