1.7. MVC Framework

Introduction

Model-View-Controller

In the design of FLOW3's architecture we have taken great care to separate concerns and assign each part of the framework with well-defined tasks. The separation of concerns is an important principle of good software design and its most prominent representative probably is the Model-View-Controller pattern. MVC separates the business logic from the presentation by splitting up user interaction into three roles:

  • The model is an object which contains data and business logic of a certain domain. It doesn't contain any information about the presentation of that data, but rather defines the behaviour. In the FLOW3 project we prefer a special kind of model, the Domain Model.

  • The view represents the display of the model on the web or another output channel. Views only display data, they don't build or modify it.

  • The controller reacts on user input, selects and manipulates the model as accordingly, selects a view and passes it the prepared model for rendering.

This diagram outlines the collaboration between model, view and controller:

Figure 1.1. Model-View-Controller Pattern

Model-View-Controller Pattern


Other Patterns Used

Design Patterns (and MVC is one of them) are not only great for solving reoccuring design problems in a structured manner - they also help you communicating software designs. The following patterns play an important role in FLOW3's MVC mechanism and might give you a better idea of the overall design:

Hello World!

Let's start with an example before we go into greater detail of request handling and the internals of the MVC framework. The minimal approach is to create an Action Controller which just returns “Hello World!”. To begin with, we need to create some directories which contain the code of our FLOW3 package and eventually the controller class:

Packages/

  Demo/

    Classes/

      Controller/

        F3_Demo_Controller_Default.php

The Default Controller class looks as simple as this (leaving out the very recommended comments):

Example 1.30. Hello World! controller

class F3_Demo_Controller_Default extends F3_FLOW3_MVC_Controller_ActionController {
   public function defaultAction() {
      return "Hello World!";
   }
}


Provided that the web root directory of your local server points to FLOW3's public/ directory, you will get the following output when calling the URI http://localhost/demo/:

Hello World!

Great, that was easy - but didn't we say that it's the view's responsibility to take care of the presentation? Let's create a simple PHP-based view for that purpose:

Packages/

  Demo/

    Classes/

      Controller/

        F3_Demo_Controller_Default.php

      View/

        Default/

          F3_Demo_View_Default_Default.php

The view's code is equally trivial:

Example 1.31. Hello World! view

class F3_Demo_View_Default_Default extends F3_FLOW3_MVC_View_Abstract {
   public function render() {
      return "Hello World!";
   }
}


Finally our action controller needs a little tweak to return the rendered view instead of shouting “Hello World!” itself:

Example 1.32. Improved Hello World! controller

class F3_Demo_Controller_Default extends F3_FLOW3_MVC_Controller_ActionController {
   public function defaultAction() {
      return $this->view->render();
   }
}


Recommended File Structure

As you have seen in the hello world example, conventions for the directory layout simplify your development a lot. There's no need to register controllers, actions or views if you follow our recommended file structure. These are the rules:

  • Controllers are located in their own directory Controller just below the Classes directory of your package. They can have arbitrary names while the Default controller has a special meaning: If the package was specified in the request but no controller, the Default controller will be used.

  • View classes are situated below a View directory. They are grouped by controllers and named by their actions: Directories below the View folder are named after the controller and the view's class name refers to the action.

This sample directory layout demonstrates the above rules:

Example 1.33. Sample file structure

Packages/

  Demo/

    Classes/

      Controller/

        F3_Demo_Controller_Default.php

        F3_Demo_Controller_Customer.php

        F3_Demo_Controller_Order.php

      View/

        Default/

          F3_Demo_View_Default_Default.php

        Customer/

          F3_Demo_View_Customer_Default.php

          F3_Demo_View_Customer_List.php

          F3_Demo_View_Customer_Details.php

        Order/

          F3_Demo_View_Order_List.php



Adhering to these conventions has the advantage that views for example are resolved automatically. However it is possible (and not really difficult) to deviate from this layout and have a completely different structure.

Request and Response

No matter if a FLOW3 application runs in a web context or is launched from the command line, the basic workflow is always the same: The user request is analyzed and forwarded to an appropriate controller which decides on which actions to take and finally returns a response which is handed over to the user. This section highlights the flow and the collaborators in the request-response machinery.

Request Processing Overview

A sequence diagram is worth a thousand words said my grandma, so let's take a look at the standard request-response workflow in FLOW3:

Figure 1.2. Example of a Web Request-Response Workflow

Example of a Web Request-Response Workflow


As you see, there are a lot of parts of the framework involved for answering a request - and the diagram doesn't even consider caching or forwarding of requests. But we didn't create this structure just for the fun of it - each component plays an important role as you'll see in the next sections.

Request Handler

The request handler takes the important task to handle and respond to a request. There exists exactly one request handler for each request type. By default web and command line requests are supported, but more specialized request handlers can be registered, too.

Before one of the request handlers comes to play, the framework needs to determine which of them is the most suitable for the current request. The request handler resolver asks all of the registered request handlers to rate on a scale how well they can handle the current raw request. The resolver then chooses the request handler with the most points and passes over the control.

Request Builder

When a request handler receives a raw request, it needs to build a request object which can be passed to the dispatcher and later to the controller. The request building delegated to a request builder which can build the required request type (ie. web, CLI etc.).

The building process mainly consists of

  1. create a new request object

  2. set some request-type specific parameters (like the request URI for a web request)

  3. determine and set the responsible controller, action and action arguments

Especially the last step is important and requires some more or less complex routing in case of web requests.

Request Processors

Requests which were built by the request builder usually fit the most common needs. For special demands it is possible to postprocess the request object before it is sent to the dispatcher. Request processors can be registered through the Request Processor Chain Manager and are - as the name suggests - invoked in a chain.

Request Dispatcher

The final task of the MVC framework consists in dispatching the request to the controller specified in the request object. The request dispatcher will try to call the action specified in the request object and if none was specified fall back on a default action.

Note

There are more features planned for the dispatcher, but at the time of this writing they have not yet been implemented.

Request Types

FLOW3 supports the most important request types out of the box. Additional request types can easily be implemented by extending the F3_FLOW3_MVC_Request class and registering a request handling which can handle the new request type (and takes care of building the request object). Here are the request types which come with the default FLOW3 distribution:

Web Request / Response

Web requests are the most common request types. Currently only the basic features are implemented, but further options - especially for the web response - are in the pipeline.

CLI Request / Response

Requests from the command line are recognized by the used SAPI (Server Application Programming Interface). This request type is basically the same as the generic request type and mainly exists as a marker.

AJAX Request / Response

Note

This request type has not yet been implemented

Controller

Action Controller

Initialization Methods

initializeController

initializeAction

initializeView

Configuration

Supported Request Types

Arguments

Action Methods

$this->defaultActionMethodName

Action View

- $this->initializeView = TRUE | FALSE

Other Controllers

Abstract Controller

Request Handling Controller

Default Controller

View

Template View

Special Views

Default View

Empty View

Helpers

Model

Routing