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

Creating A New Model

We'll use the Agavi build script to generate the two models we need. As they belong to the posts handling part of our application, we'll create them in the in the Posts module:

 bloggie$ dev/bin/agavi model-create

 Module name: Posts

 Model name: Post

 bloggie$ 
      

This will create the Posts_PostModel in the directory app/modules/Posts/models/. The class will be empty for now, we'll add code to it in a second. First, let's repeat the same steps for the PostManager model.

 bloggie$ dev/bin/agavi model-create

 Module name: Posts

 Model name: PostManager

 bloggie$ 
      

Now you should have two files in app/modules/Posts/models/, one named PostModel.class.php, one named PostManagerModel.class.php containing the empty classes Posts_PostModel and Posts_PostManagerModel. Note how both classnames are prefixed with the module's name and that they both end in "Model". This convention is used through out agavi. While it is possible to reference models that have different naming schemes we recommend sticking to this convention.

Both models extend the BlogPostsBaseModel class that was created when we created the module.

Instantiating Models

Now that we created the model classes, we need a way to create instances. We could go the long route with including the class file, creating a new instance with new Posts_PostModel and then calling the required initialize() method. However, there is an easier way. Any object with access to the AgaviContext (which is pretty much every object in the framework) can just call $ctx->getModel(<modelname>, <modulename>, <optional parameters>) to create a fully initialized instance of the given model. The context will then locate the proper class file, load it if required, and return an initialized instance of the requested model.

Fleshing Out The Models

Let's add a bit of functionality to the models. The Post model currently is just a container for the data a Post can have, so we'll primarily add the attributes and getters and setters for those attributes and throw in two methods to create a post from an array of values and reverse. Your final Posts_PostModel [app/modules/Posts/models/PostModel.class.php] should look like that (the comments are left out to keep it short):

 
<?php

class Posts_PostModel extends BlogPostsBaseModel
{
  private $id;
  private $title;
  private $posted;
  private $categoryName;
  private $authorName;
  private $content;

  public function __construct(array $data = null)
  {
    if(!empty($data))
    {
      $this->fromArray($data);
    }
  }

  public function getId()
  {
    return $this->id;
  }

  public function setId($id)
  {
    $this->id = $id;
  }

  public function getTitle()
  {
    return $this->title;
  }

  public function setTitle($title)
  {
    $this->title = $title;
  }

  public function getPosted()
  {
    return $this->posted;
  }

  public function setPosted($posted)
  {
    $this->posted = $posted;
  }

  public function getCategoryName()
  {
    return $this->categoryName;
  }

  public function setCategoryName($name)
  {
    $this->categoryName = $name;
  }

  public function getAuthorName()
  {
    return $this->authorName;
  }

  public function setAuthorName($name)
  {
    $this->authorName = $name;
  }

  public function getContent()
  {
    return $this->content;
  }

  public function setContent($content)
  {
    $this->content = $content;
  }

  public function fromArray(array $data)
  {
    $this->setId($data['id']);
    $this->setTitle($data['title']);
    $this->setPosted($data['posted']);
    $this->setCategoryName($data['category_name']);
    $this->setAuthorName($data['author_name']);
    $this->setContent($data['content']);
  }

  public function toArray()
  {
    $data = array();
    $data['id'] = $this->getId();
    $data['title'] = $this->getTitle();
    $data['posted'] = $this->getPosted();
    $data['category_name'] = $this->getCategoryName();
    $data['author_name'] = $this->getAuthorName();
    $data['content'] = $this->getContent();

    return $data;
  }
}

?>

The Posts_PostManageModel [app/modules/Posts/models/PostManager.class.php] is responsible for all storage and retrieval operations. We currently need two operations: Retrieve a single Post and retrieve the latest posts for the front page. As we now do have a model encapsulating all the data retrieval we can move our mock-data into that model. The end result should look like this:

<?php

class Posts_PostManagerModel extends BlogPostsBaseModel
{
  private $posts = array(
    1 => array(
      'id' => 1,
      'title' => 'First post',
      'posted' => '2008-07-14 00:01:07',
      'category_name' => 'No category',
      'author_name' => 'Admin',
      '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',
      'content' => '<p>It looks like our blog application is working, yay!</p>',
    )
  );

  public function retrieveById($id)
  {
    if (isset($this->posts[$id]))
    {
      return $this->getContext()->getModel('Post', 'Posts', array($this->posts[$id]));
    }
  
    return null;
  }
  
  public function retrieveLatest($limit = 5)
  {
    $cnt = 0;
    reset($this->posts);
    
    $posts = array();
    
    foreach($this->posts as $post) {
      $posts[] = $this->getContext()->getModel('Post', 'Posts', array($post));
      $cnt++;
      if($cnt >= $limit) {
        break;
      }
    }
    
    return $posts;
  }
  
}

?>