Deprecated/0.10/UsingDecorators

Warning! This page has the following tags:

  • This page is deprecated, and is only useful for developers using Agavi 0.10.
  • This page exists for reference purposes only.

Using Decorators in Agavi

As the name says, Decorators decorate your Action. Well, not exactly the Action, but rather the View, and the more I think about it, it is actually the template that is decorated, although you're essentially decorating what the Action does and setting the Decorator up inside your View code.

So What's a Decorator, Then?

Uh yeah. Sorry. I think a picture is suited best to explain it. Phear my ASCII art drawing skillz!

+-------------------------------------------+
|                                           |
|  Your beloved Decorator   +-------------+ |
|                           | Oh darling, | |
|  +--------------------+   | look, the   | |
|  |                    |   | decorator   | |
|  |   Your Action,     |   | has a slot! | |
|  |   It's inside!     |   | How cute!   | |
|  |                    |   +-------------+ |
|  +--------------------+                   |
|                                           |
+-------------------------------------------+

I Still Don't Know Jack

Yeah okay, you're right, I should have tried to mock something up using Paint instead. Anyway... the only thing that gets called is that Action in there. All the rest, i.e. the Decorator and the slot, is defined inside your View. It "decorates" your Action output and can be used to add that opening and closing HTML around your content. Ideally, your action template only outputs what is necessary - an article, a contact form, the start page of your site, whatever.

Okay... But What Are These Slots All About?

You swap out functionality to Slots. This way, you Don't Repeat Yourself (tm). You write less code, you make stuff more portable. As a rule of thumb, you should move every component that is used more than once in your page to it's own Slot. Like, for example, a breadcrumb navigation. Or a menu bar. Or the "random item" box. Note that you can also nest decorators, and if you are using plenty of actions, it might be wise to create a seperate View that you subclass your own views from which sets up the basic decorator that is used everywhere, and registers the common denominator of Slots used.

Right, Right, Mister Know-It-All, How do I Use It?

ShowArticleAction.class.php:

<?php
class ShowArticleAction extends Action
{
  public function execute()
  {
    $this->getContext()->getRequest()->setAttribute('article', 'This is my article, blah, blah, blah!');
    $this->getContext()->getRequest()->setAttribute('title', 'The Title of the Article');
    return View::SUCCESS;
  }
}
?>

ShowArticleSuccessView.class.php:

<?php
class ShowArticleSuccessView extends PHPView
{
  public function execute()
  {
    $this->setDecoratorTemplate('Master.php');
    $this->setSlot('menu', 'Default', 'Menu');

    $this->setTemplate('ShowArticleSuccess.php');

    $this->setAttribute('title', $this->getContext()->getRequest()->getAttribute('title'));
    $this->setAttribute('article', $this->getContext()->getRequest()->getAttribute('article'));
  }
}
?>

MenuAction.class.php:

<?php
class MenuAction extends Action
{
  public function execute()
  {
    $menuItems = array();
    $menuItems[] = array('url' => 'http://www.yahoo.com/', 'name' => 'Yahoo');
    $menuItems[] = array('url' => 'http://www.google.com/', 'name' => 'Google');
    $menuItems[] = array('url' => 'http://www.cnn.com/', 'name' => 'CNN');
    $this->getContext()->getRequest()->setAttribute('menuItems', $menuItems);
    return View::SUCCESS;
  }
}
?>

MenuSuccessView.class.php:

<?php
class MenuSuccessView extends PHPView
{
  public function execute()
  {
    $this->setTemplate('MenuSuccess.php');
    $this->setAttribute('menuItems', $this->getContext()->getRequest()->getAttribute('menuItems'));
  }
}
?>

ShowArticleSuccess.php:

<h1><?=$template['title']?></h1>
<p><?=$template['article']?></p>

MenuSuccess.php:

<ul>
<?php foreach($template['menuItems'] as $item): ?>
  <li><a href="<?=$item['url']?>"><?=$item['name']?></a></li>
<?php endforeach; ?>
</ul>

Master.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html>
  <head>
  <title><?=$template['title']?> - My Cool Website</title>
  </head>
  <body>
    <?=$template['menu']?>
    <hr />
    <?=$template['content']?>
  </body>
</html>

Now call your index.php?module=Default&action=ShowArticle to see the magic. The resulting HTML will be:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html>
  <head>
  <title>The Title of the Article - My Cool Website</title>
  </head>
  <body>
    <ul>
      <li><a href="http://www.yahoo.com/">Yahoo</a></li>
      <li><a href="http://www.google.com/">Google</a></li>
      <li><a href="http://www.cnn.com/">CNN</a></li>
    </ul>
    <hr />
    <h1>The Title of the Article</h1>
    <p>this is my article, blah, blah, blah!</p>
  </body>
</html>

The only thing you also need to know is these two things:

  • The output of the called Action's View is available inside $templatecontent? in the decorator template
  • All variables assigned inside the Action's View are also available in the decorator template (we're putting the article title into the document title here)