3

I want to plug twig into an application that would need some session-based data incorporated in the base. For example, the client's current timezone shows in the footer. It doesn't make sense for the individual controllers to know about this, since it has nothing to do with them; but on the other hand, they select and populate the view:

class MyController 
{

    public function index()
    {
        $template = $this->twig->loadTemplate('myPageTemplate.html.twig');
        return $template->render($dataArray);
    }
}

Is there some well-formed way to pass a data object to twig before you select a view, and make that available to the base template? Something that you would do upon firing up the Twig_Environment and passing it in?

Bryan Agee
  • 4,924
  • 3
  • 26
  • 42

3 Answers3

1

Session variables need to be set in a controller. As can be seen in the docs, it would look something like this:

public function indexAction(Request $request)
{
    $session = $request->getSession();

    // store an attribute for reuse during a later user request
    $session->set('foo', 'bar');

    // get the attribute set by another controller in another request
    $foobar = $session->get('foobar');

    // use a default value if the attribute doesn't exist
    $filters = $session->get('filters', array());
}

Those variables are then easily passed when rendering a template with something like:

return $this->redirect($this->generateUrl('home', array('foobar' => $foobar)));
geoB
  • 4,578
  • 5
  • 37
  • 70
1

If you don't want all of your controllers to deal with the injection of those "global" variables, you can implement a base controller class that all other controllers inherit from and do the following inside:

public function render($view, array $parameters = array(), Response $response = null)
{
    if(!isset($parameters['timezone'])) {
         // fill the parameter with some value
        $parameters['timezone'] = $this->getSession()->get('timezone');
    }
    return parent::render($view, $parameters, $response);
}

This allows you to do a "global" injection without giving control completely away from the controllers.

Don't forget to make your base controller extend Symfony\Bundle\FrameworkBundle\Controller\Controller.

janwschaefer
  • 609
  • 3
  • 6
  • This looks like a smart, clean way to get it done; I'm not quite sure yet if I want all my controllers extending a base, though... – Bryan Agee Aug 09 '14 at 22:41
  • They do anyways when you inherit from Symfony\Bundle\FrameworkBundle\Controller\Controller. – janwschaefer Aug 09 '14 at 22:41
  • @janwschaefer- We're not using a full symfony stack yet--just plugging in some of the compenents. As yet, the controllers are not extending anything – Bryan Agee Aug 09 '14 at 22:43
  • I see. You can maybe take this a step further. Look in the implementation of render() in the base controller provided by symfony. They call return $this->container->get('templating')->renderResponse($view, $parameters, $response); So you can just extend that service, do the hack i proposed in renderResponse and use your own service instead for templating. – janwschaefer Aug 09 '14 at 22:45
  • How do you populate the twig field in your controller? Using the service container? – janwschaefer Aug 09 '14 at 22:54
1

The best approach would be adding a Twig extension so you don’t have to include anything in your controller. With the extension you can either add a global as someone already suggested (http://twig.sensiolabs.org/doc/advanced.html#globals) or functions (http://twig.sensiolabs.org/doc/advanced.html#functions) which you can then use directly (like {{ user_timezone() }} ).

hacfi
  • 756
  • 3
  • 7