3.3. Module / Page Component Architecture and Action Events

Now that the data model is built, we can move on to the User Interface. Before we actually build a user interface for our blog application, let's explore the concepts used by PHOCOA to build your UI.

One of the drawbacks of "normal" web application development is that you have to do a lot of work completely unrelated to your application to make it work as a web app. The conceptual goal of PHOCOA (or any web application framework, for that matter) is to provide you with an infrastructure to minimize the amount of non-application-specific code you have to write. PHOCOA is organized in such a way as to abstract away all of the complications of building software for the web, and lets you focus entirely on building the logic and UI for your application.

PHOCOA accomplishes this by handling all aspects of the web application, and calling into your applications' custom code at the appropriate times to allow you to implement your business and interface logic.

The user interface is managed by the View and Controller portions of the MVC programming model. PHOCOA borrows from Cocoa again, translating the concept of nib files and the controller layer to the web.


The basic unit of work in a PHOCOA application is the module. A module is a collection of web pages (the Views of MVC) and code (the Controllers of MVC) related to a single function of your web application. For instance, you might have a module for editing and previewing a blog post, and a separate module for displaying the blog post to the public.

Each PHOCOA module is a single PHP file that contains a single WFModule subclass, and optionally a WFPageDelegate class for each page in the module.

There is a naming convention to the WFModule subclass names. The subclass should be named module_<moduleName> where <moduleName> is the name of the directory that the module sits in. This helps prevent name collisions with other classes. The page delegates follow a similar convention; the page delegate class should be named module_<moduleName>_<pageName>.

Because each module contains all of the code and web pages to handle a specific function, each module in PHOCOA is also an easily reusable web component. The components can be used one-at-a-time to build complete pages, or you can composite modules together to create complex layouts and behaviors.

When you finish a module, you have a set of functional web pages to manage a certain aspect of your web application. You also have an API for accessing these functions.

Modules are invoked via an invocationPath which looks like path/to/module/pageName/param1/param2. Obviously this looks a lot like a URL. When you go to a URL of a PHOCOA application, the request controller parses out the invocationPath from the URL and executes the module. Modules that include other modules simply supply the invocationPath directly.

Modules contain the shared objects used by the module's pages. These are declared in the shared.yaml file. Think of shared.yaml as your nib file, and the module class as the File's Owner.


Each module can contain an arbitrary number of pages. A page is simply a single web view that a user can see. You can think of it as a web page, a view, a screen, whatever works for you. For instance, you may have one view that is an input form, and another view that is used for telling the user the form's action succeeded.

While in Cocoa you would instantiate all of the UI widgets in the nib file, in PHOCOA each page has its own yaml file which contains all of the UI widgets for that page.


Each page has a number of actions. Actions are trigger by the user submitting a form. When the user submits a form, PHOCOA will hand off control to an action handler in your module where you can respond to the action.

It should be noted that not all requests have actions. It is possible to just load a page in a module WITHOUT an action. In this case, the module can display the default page, or could look in the parameters passed to it to find information used to load default data into the page.

Actions are implemented by the user by implementing an action callback handler, a method with the signature:

function doAction($page, $params);

Where "doAction" is replaced with the name of your action (which is by default the name of the submit widget).

Additionally, if there is NO action to be taken on this request, this special callback is executed:

function noAction($page, $params);

Page Life Cycle

PHOCOA handles all aspects of the web page request automatically, and allows your page to simply "chime in" at appropriate times to implement business logic. The WFPageDelegate interface documents all of the different callbacks your page can implement to create your page's business logic. Below is a brief description of the page life cycle callbacks, in the order in which they occur.

function pageInstancesDidLoad($page); // the page's UI has been restored from the serialized state (YAML file).

function parameterList(); // called to get the list of parameters supported by this page.

function parametersDidLoad($page, $params); // the page's parameters are loaded. typically you will load your data in this callback.

function willPushBindings($page, $params); // the changes made on the client are about to be batch-applied to the current state of the application.

function doAction($page, $params); // the action method is called all batch-applied changes are made without error

function noAction($page, $params); // the page has loaded, but no action has been executed

function setupSkin($page, $parameters, $skin); // allow the page to customize the skin being used

function willRenderPage($page, $parameters); // page is about to be rendered

function didRenderPage($page, $parameters, &$output); // page has been rendered but not output to client