Destroy every zig! The official Gerry Vandermaesen blog

6Oct/102

Making template vars available in the layout

By default in symfony, the only way to make variables available to the layout/decorator is using slots. This can be a bit cumbersome.

While I welcome your feedback on possible cons of doing such a thing, making all assigned template variables available to the layout as well is quite straightforward by extending sfPHPView.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
 
class myPHPView extends sfPHPView
{
 
  /**
   * Loop through all template slots and fill them in with the results of presentation data.
   *
   * @param  string $content  A chunk of decorator content
   *
   * @return string A decorated template
   */
  protected function decorate($content)
  {
    if (sfConfig::get('sf_logging_enabled'))
    {
      $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Decorate content with "%s/%s"', $this->getDecoratorDirectory(), $this->getDecoratorTemplate()))));
    }
 
    // set the decorator content as an attribute
    $attributeHolder = $this->attributeHolder;
 
    $attributes = array_merge($attributeHolder->getAll(), array('sf_content' => new sfOutputEscaperSafe($content)));
    $this->attributeHolder = $this->initializeAttributeHolder($attributes);
    $this->attributeHolder->set('sf_type', 'layout');
 
    // check to see if the decorator template exists
    if (!is_readable($this->getDecoratorDirectory().'/'.$this->getDecoratorTemplate()))
    {
      throw new sfRenderException(sprintf('The decorator template "%s" does not exist or is unreadable in "%s".', $this->decoratorTemplate, $this->decoratorDirectory));
    }
 
    // render the decorator template and return the result
    $ret = $this->renderFile($this->getDecoratorDirectory().'/'.$this->getDecoratorTemplate());
 
    $this->attributeHolder = $attributeHolder;
 
    return $ret;
  }
 
}

You can configure the view class to use per module in module.yml. However, if you put the following module.yml in your project dir's config it would apply the extended view class to all modules by default.

1
2
3
default:
  enabled:          true
  view_class:       myPHP

At first I was looking for a way to have my view parameters namespaced and to only assign global variables to the layout. However, both sfViewParameterHolder and sfNamespacedParameterHolder extend sfParameterHolder, so you'd probably have to do some merging of the two classes. With a little more time perhaps I'll look into a cleaner solution for this common problem.

Comments (2) Trackbacks (0)
  1. On one level I want to say “you should just use slots for this.” On another I must admit that we had to make the current page available to the layout in the Apostrophe CMS for Symfony by stepping outside of the usual paradigm (aTools::getCurrentPage()).

  2. I agree that you shouldn’t resort to this type of solutions for everything. Slots certainly fill a need, and you should stick to them as much as possible.

    However, sometimes I just want to check certain flags which can be set from inside the controller for rendering different HTML, or just assign a very simple value like an extra CSS class to the body element, and I feel slots are very (too?) verbose for such simple usecases.

    I would like to revisit this one day and have namespaced parameter holders, in a way you could implement a $this->setGlobalVar(‘foo’, true) in your actions for example.


Leave a comment

(required)

No trackbacks yet.