Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP/Symfony - Why is Exception from controller rendered with Twig not caught in Production mode only?

I have 2 controller actions and one is rendered in a twig template of the other by render(controller(...)) function. If I throw an exception inside of the child action, it gets caught only in DEV mode and not in PRODuction, any ideas why and how to get around it?

DefaultController.php

/**
 * @Route("/test/child", name="test_child")
*/
public function childAction(Request $request)
{
    throw new \Exception($request->getRequestUri());

    return $this->render("child.html.twig");
}

/**
 * @Route("/test/parent", name="test_parent")
 */
public function parentAction(Request $request)
{
    try {
        return $this->render("parent.html.twig");
    } catch(\Exception $e)
    {
        die("got it!");
    }
}

child.html.twig

Child

parent.html.twig

Parent
<br>
{{ render(controller("WebBundle:Pages:child")) }}

Result:

enter image description here

like image 746
Mike Avatar asked Apr 07 '16 14:04

Mike


People also ask

Can I use twig without Symfony?

Twig is a template engine for PHP and can be used without Symfony, although it is also made by SensioLabs.

What is Twig in Symfony?

Twig is a template engine for the PHP programming language. Its syntax originates from Jinja and Django templates. It's an open source product licensed under a BSD License and maintained by Fabien Potencier. The initial version was created by Armin Ronacher.

What is raw in twig?

Raw is a filter, thus it does not render any output: it just trasforms it. In this case, the "trasformation" consists in setting a "safe" mark on it so that the actual rendering (performed by the {{...}} tags) will not escape it.

What is Symfony exception?

In Symfony applications, all errors are treated as exceptions, no matter if they are a 404 Not Found error or a fatal error triggered by throwing some exception in your code.


1 Answers

In a Symfony2 project, Twig catch exceptions by default in production mode.

You can configure it in order that all exceptions are thrown like in dev mode:

// app/config/config.yml
twig:
    # ...
    debug: true # default: %kernel.debug%

Or, configure an exception listener:

Service declaration:

// app/config/services.yml
app.exception_listener:
    class: Acme\CoreBundle\Listener\ExceptionListener
    arguments: [ "@templating" ]
    tags:
        - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

Class:

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\Templating\EngineInterface;

class ExceptionListener
{
    private $templateEngine;

    public function __construct(EngineInterface $templateEngine)
    {
        $this->templateEngine = $templateEngine;
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $response = $this->templateEngine->render(
            'TwigBundle:Exception:error500.html.twig',
            array('status_text' => $event->getException()->getMessage())
        );
        $event->setResponse(new Response($response));
    }
}

Template for exception message trace/message displaying:

// app/Resources/TwigBundle/views/Exception/error500.html.twig
{% extends '::base.html.twig' %}

{% block body %}
    <div class='error'>
        <div class="message">
            <h2>Application Error</h2>
            <p>Oops! {{ status_text }}</p>
        </div>
    </div>
{% endblock %}

EDIT

To catch only specific exceptions, add the following at the beggining of your listener:

// Listen only on the expected exception
if (!$event->getException() instanceof RedirectException) {
    return;
}

Hope this helps.

like image 77
chalasr Avatar answered Oct 04 '22 05:10

chalasr