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

Accessing Request Parameters and Validation Basics

Now that we intruduced a parameter to pass the posts ID we could display the proper post on the detail page. All incoming parameters, including cookies, headers and files are passed to the view's executeHtml() method via a container object, an AgaviRequestDataHolder(). In the web context, a more specific subclass, an AgaviWebRequestDataHolder() is being passed. Any parameter extracted from the url, any GET or POST value can be accessed via AgaviRequestDataHolder::getParameter(<parametername>, <defaultvalue>).

Validation Basics

However, in the default setup, strict validation is turned on. That means that only validated parameters may be accessed, all other parameters are removed by the framework. While it is possible to change that behavior, we strongly recommend keeping it that way. Validation is an important part in keeping your application safe from attacks of any kind or from failure due to unexpected input. Validation makes you as a developer think about what input is valid. Always validate as strict as possible. So let's see, what's our expected input?


  • The post-id must be an integer.
  • The post-id must be in the valid range, we have two posts with the ids 1 and 2.

So let's put that into code.

How Validation Works

Validation is executed when an Action responds to the incoming request type. Validation rules are per action and may differ between read and write requests. While there are other ways of defining validation rules, in most cases they are laid out in an xml-configuration file, so that's all we'll do at this point. We'll deal with the other methods later. In the default setup the XML file is named like the action and placed in the folder validate/ in the corresponding module. The build system created a stub file for us, it's located in app/modules/Posts/validate/Posts/Show.xml and for now only contains a stub. Let's extend it to look like that:

<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations
  xmlns="http://agavi.org/agavi/config/parts/validators/1.0"
  xmlns:ae="http://agavi.org/agavi/config/global/envelope/1.0"
  parent="%core.module_dir%/Posts/config/validators.xml"
>
  <ae:configuration>

    <validators>
      <validator class="number" name="post">
        <arguments>
          <argument>post</argument>
        </arguments>
        <errors>
          <error>The parameter post must contain a number in the range of 1 - 2</error>
        </errors>
        <ae:parameters>
          <ae:parameter name="type">int</ae:parameter>
          <ae:parameter name="min">1</ae:parameter>
          <ae:parameter name="max">2</ae:parameter>
        </ae:parameters> 
      </validator>
    </validators>

  </ae:configuration>
</ae:configurations>
  

This defines a single validator with the name "post" and the class "number". The name is optional and can be used to get detailed information about where validation failed. In most cases you won't need it. The class-attribute controls which validator is run. It can either be a predefined shortname or real classname in case you want to use a custom validator. The <arguments> block defines on which parameters the validator is run. Some validators may work on multiple parameters, for example a validator checking that two parameters are equal. In our case we only need a single parameter named "post". The <errors> block controls which error message is emitted if the validator fails. We could have different messages for different errors, one if the value was not provided at all, one if it was no valid integer, another one if it was out of range. In this case a generic message is just fine. The parameters block allows more fine-grained control over the validator behavior. The parameters a validator accepts differ from validator to validator and may sometimes seem a little complex, but the AgaviNumberValidator we're using here is pretty straightforward. It allows a type, a minimum value and a maximum value.

With this validation file we've checked that the incoming data is all fine and we can rely in the rest of the application on that.

Displaying The Right Post

Now that we validated the incoming post-id we can display the requested post on our detail page. For the time being we just copy the static posts array that we used for the list and pick the right one of the two. Change the Posts_PostShowAction::executeRead() [app/modules/Posts/actions/Posts/ShowAction.class.php] to look like this:

public function executeRead(AgaviRequestDataHolder $rd)
{
   $posts = array(
    1 => array(
      'id' => 1,
      'title' => 'First post',
      'posted' => '2008-07-14 00:01:07',
      'category_name' => 'No category',
      'author_name' => 'Admin',
      'url' => null,
      'content' => '<p>Terrific! This is our first post!</p><p>This is just a first post. It has no actual contents. If you are reading this, things must be working.</p>',
    ),
    2 => array(
      'id' => 2,
      'title' => 'Second post',
      'posted' => '2008-07-14 00:01:07',
      'category_name' => 'Agavi',
      'author_name' => 'Admin',
      'url' => null,
      'content' => '<p>It looks like our blog application is working, yay!</p>', 
    )
  );

  $postId = $rd->getParameter('post');
  $post = $posts[$postId];
    
  $this->setAttribute('post', $post);

  return 'Success';
}

We don't have to check whether the array key exists because we validated the incoming parameter and the constraints are set strict enough that the valid cannot be out of range. And see how the separation of display and logic already worked in our favor? There was no need to adapt the view or the template even though we changed the logic reading the data.