2
votes

I am trying to render template not using the Symfony2 required format 'Bundle:Controller:file_name', but want to render the template from some custom location.

The code in controller throws an exception

Catchable Fatal Error: Object of class __TwigTemplate_509979806d1e38b0f3f78d743b547a88 could not be converted to string in Symfony/vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle/Debug/TimedTwigEngine.php line 50

My code:

$loader = new \Twig_Loader_Filesystem('/path/to/templates/');
$twig = new \Twig_Environment($loader, array(
    'cache' => __DIR__.'/../../../../app/cache/custom',
));
$tmpl = $twig->loadTemplate('index.twig.html');
return $this->render($tmpl);

Is it even possible to do such things in Symfony, or we have to use only logical names format?

1

1 Answers

9
votes

Solution

You could do the following, replacing your last line return $this->render($tmpl);:

$response = new Response();
$response->setContent($tmpl);
return $response;

Don't forget to put a use Symfony\Component\HttpFoundation\Response; at the top of your controller though!

Theory

Alright, let's begin from where you are now. You are inside your controller, calling the render method. This method is defined as follows:

/**
 * Renders a view.
 *
 * @param string   $view       The view name
 * @param array    $parameters An array of parameters to pass to the view
 * @param Response $response   A response instance
 *
 * @return Response A Response instance
 */
public function render($view, array $parameters = array(), Response $response = null)
{
    return $this->container->get('templating')->renderResponse($view, $parameters, $response);
}

The docblock tells you that it expects a string which is the view name, not an actual template. As you can see, it uses the templating service and simply passed the parameters and return value back and forth.

Running php app/console container:debug shows you a list of all registered services. You can see that templating is actual an instance of Symfony\Bundle\TwigBundle\TwigEngine. The method renderResponse has the following implementation:

/**
 * Renders a view and returns a Response.
 *
 * @param string   $view       The view name
 * @param array    $parameters An array of parameters to pass to the view
 * @param Response $response   A Response instance
 *
 * @return Response A Response instance
 */
public function renderResponse($view, array $parameters = array(), Response $response = null)
{
    if (null === $response) {
        $response = new Response();
    }

    $response->setContent($this->render($view, $parameters));

    return $response;
}

You now know that when you call the render method, a Response object is passed back which is essentially a plain Response object on which setContent was executed, using a string representing the template.

I hope you don't mind I described it a bit more detailed. I did this to show you how to find a solution like this yourself.