1. Introduction
    1. About Agavi
    2. MVC in Agavi
    3. Overview of Agavi
    4. Overview of Application Execution Flow
    5. A Word About Actions
    6. Application filesystem layout
    7. Overview of application configuration
  2. Setting Up The Initial Application
    1. Installing Agavi
    2. Creating an Agavi Project
    3. Finishing The Setup
    4. Finishing The Basic Setup
    5. Installing a New Copy of Your Application
  3. Adding First Code
    1. Creating A New module
    2. Creating A New Action
    3. Tying Things Together — An Introduction To Routing
    4. Fixing The Bloggie Routing
    5. Accessing Request Parameters and Validation Basics
    6. Handling Validation Errors
  4. Putting The M in MVC
    1. Creating A New Model
    2. Adapting The Actions and Views
    3. Custom Validators
  5. Polishing It Up
    1. Layers and Layouts
    2. Applying Our Layout
    3. What Are Slots?
    4. Adding The Post's Title To The URL
    5. Routing Callbacks
    6. Using Callbacks for the Title in URLs
  6. Connecting to a database
    1. The Database Manager
  7. Handling Output Variants
    1. Output Types
    2. Exception Templates
    3. Generating an RSS Feed
  8. Form Processing
    1. Adding a Post
    2. Editing a Post
    3. The Form Population Filter (FPF)
  9. Creating a User Authentication System
  10. Adding To The Master Template

Output Types

Output types is Agavi's way of dealing with the requirement of having multiple presentation formats for a ressource. For example, a list of items could be delivered to the client as a regular plain HTML list, a json serialized array of objects, as a SOAP response or even rendered as an image or chart if required.

Output types are configured in app/config/output_types.xml. An output type configuration can specify a variety of parameters:


  • A name. Each output type must have a unique name.
  • A set of HTTP headers to send with the response, most notably the content-type header. These headers can be overwritten later but it's still good practice to define a reasonable default set.
  • A specific exeption template to use in case an uncaught exception occurs.
  • A renderer configuration, including the renderer to use and any parameters required for rendering.
  • Any number of preconfigured layouts.

Except for the output type name, all of these parameters are optional. There's quite a few output types where using a renderer wouldn't make sense, for example a json serialized response.

Let's have a look at the stock HTML output type from the standard generated application:

...
<output_types default="html">
  
  <output_type name="html" exception_template="%core.template_dir%/exceptions/web-html.php">
    
    <renderers default="php">
      <renderer name="php" class="AgaviPhpRenderer">
        <ae:parameter name="assigns">
          <ae:parameter name="routing">ro</ae:parameter>
          <ae:parameter name="request">rq</ae:parameter>
          <ae:parameter name="controller">ct</ae:parameter>
          <ae:parameter name="user">us</ae:parameter>
          <ae:parameter name="translation_manager">tm</ae:parameter>
          <ae:parameter name="request_data">rd</ae:parameter>
        </ae:parameter>
        <ae:parameter name="default_extension">.php</ae:parameter>
        <!-- this changes the name of the variable with all template attributes from the default $template to $t -->
        <ae:parameter name="var_name">t</ae:parameter>
      </renderer>
    </renderers>
    
    <layouts default="standard">
      <!-- standard layout with a content and a decorator layer -->
      <layout name="standard">
        <!-- content layer without further params. this means the standard template is used, i.e. the one with the same name as the current view -->
        <layer name="content" />
        <!-- decorator layer with the HTML skeleton, navigation etc; set to a specific template here -->
        <layer name="decorator">
          <ae:parameter name="directory">%core.template_dir%</ae:parameter>
          <ae:parameter name="template">Master</ae:parameter>
          <slots>
            <slot name="navigation" module="Widgets" action="Navigation" />
            <slot name="header" module="Widgets" action="Header" />
            <slot name="footer" module="Widgets" action="Footer" />
            <slot name="dashboard" module="Widgets" action="Dashboard" />
            <slot name="sidebar" module="Widgets" action="Sidebar" />  
          </slots>
        </layer>
      </layout>
      
      <!-- another example layout that has an intermediate wrapper layer in between content and decorator -->
      <!-- it also shows how to use slots etc -->
      <layout name="wrapped">
        <!-- content layer without further params. this means the standard template is used, i.e. the one with the same name as the current view -->
        <layer name="content" />
        <layer name="wrapper">
          <!-- use CurrentView.wrapper.php instead of CurrentView.php as the template for this one -->
          <ae:parameter name="extension">.wrapper.php</ae:parameter>
        </layer>
        <!-- decorator layer with the HTML skeleton, navigation etc; set to a specific template here -->
        <layer name="decorator">
          <ae:parameter name="directory">%core.template_dir%</ae:parameter>
          <ae:parameter name="template">Master</ae:parameter>
          <!-- an example for a slot -->
          <slot name="nav" module="Default" action="Widgets.Navigation" />
        </layer>
      </layout>
      
      <!-- special layout for slots that only has a content layer to prevent the obvious infinite loop that would otherwise occur if the decorator layer has slots assigned in the layout; this is loaded automatically by ProjectBaseView::setupHtml() in case the current container is run as a slot -->
      <layout name="slot">
        <layer name="content" />
      </layout>
    </layouts>
    
    <ae:parameter name="http_headers">
      <ae:parameter name="Content-Type">text/html; charset=UTF-8</ae:parameter>
    </ae:parameter>
    
  </output_type>

</output_types>
...
We've already had a look at the layout definition so we'll skip that at this point. Please refer to the chapter about layouts. The parameter exception_template sets a specific exception template for this output type.
CAUTION:
You should use a custom exception template - and if you do so double check that it's sending a correct 500 Internal Server Error status code. You don't want your error page to end up in caches or even worse on google.
The section <renderers> specifies a list of renderers:
<renderers default="php">
  <renderer name="php" class="AgaviPhpRenderer">
    <ae:parameter name="assigns">
      <ae:parameter name="routing">ro</ae:parameter>
      <ae:parameter name="request">rq</ae:parameter>
      <ae:parameter name="controller">ct</ae:parameter>
      <ae:parameter name="user">us</ae:parameter>
      <ae:parameter name="translation_manager">tm</ae:parameter>
      <ae:parameter name="request_data">rd</ae:parameter>
    </ae:parameter>
    <ae:parameter name="default_extension">.php</ae:parameter>
    <!-- this changes the name of the variable with all template attributes from the default $template to $t -->
    <ae:parameter name="var_name">t</ae:parameter>
  </renderer>
</renderers>

This specifies a single renderer named "php" that uses the default AgaviPhpRenderer. This renderer is the default renderer used. The <assigns> tag controls which internal objects are available in the template and their respective variable name. The parameter named default_extension sets the expected template extension to ".php". The var_name parameter controls the name of the template variable.

Then there's the last section named "http_headers":

<ae:parameter name="http_headers">
  <ae:parameter name="Content-Type">text/html; charset=UTF-8</ae:parameter>
</ae:parameter>

This section contains a list of default HTTP headers to send. In most cases it's reasonable to at least list a default content-type header here.

Rendering for a specific output type

The framework calls a method named execute<OutputTypeName> on the view to render. So for an HTML output type the method executeHtml() is called on a view, for a JSON output type executeJson() etc. The method can either return a valid response content or set up layers to render or even both. Valid response content may be


  • A string.
  • An open file pointer. Agavi will stream the contents of that file to the user with the most efficient method available.

Using a specific output type

The output type to use can either be set on the container using the setOutputType method, by passing an output type name to createSlotContainer() when creating a slot, by passing the output type to createForwardContainer() when doing an internal forward or by the routing.

The any route can use the "output_type" attribute to set the active output type. A standard example is setting output types based on the file extension using a non-stopping route:

 <route name="ot_xml" pattern=".xml$" cut="true" output_type="xml" />

This route would match any url ending in ".xml", strip the extension, set the output type to "xml" and then continue processing. The output type must be configured to to use this facility.