简体   繁体   中英

Symfony2 exception controller renders into existing content in case of Fatal Errors

I'm throwing an exception from within my template's code, somewhere near the end of my templates:

...
{{ offer.throwError() }}
...

Offer::throwError:

 public function throwError() {
        $foo = $this->getAdvantageText()->getFoo(); //fatal error
        throw new \Exception("blah"); //only exception
    }

Having not customized anything I expect to have an error page rendered as response (using Twig's default ExceptionController which we in fact want to override). When Offer::getAdvantageText() is === null a FatalErrorException is raised and the error page contents are written directly into the markup at the place where the exception is thrown. When I just throw the custom exception, it works as expected (a single error page is shown). When I debug into ExceptionController, it is supposed to explicitly clear the output buffer:

Twig/ExceptionController:

 protected function getAndCleanOutputBuffering($startObLevel)
    {
        if (ob_get_level() <= $startObLevel) {
            return '';
        }

        Response::closeOutputBuffers($startObLevel + 1, true);

        return ob_get_clean();
    }

but in all my fatal error cases ob_get_level is <= $startObLevel (handed over by kernel, in my case "2"). We don't have application / gateway caching in place (yet). When I manually clear the output buffer in that situation, the page is "cleared" and I get a single error page response as expected. As far as I can see there's no fragment rendering in place (that would've issued a subrequest).

I thought about utilizing the kernel.exception event and clear everything on my own but I think just customizing the controller should do the trick anyway. It seems that the "fatal" error is interfering with the ob-stack of Symfony's kernel but I can't see how to work around that issue.

I've got a preliminary solution to address that issue. In my custom exception controller I also overwrite the getAndCleanOutputBuffering method:

protected function getAndCleanOutputBuffering($startObLevel)
{
    Response::closeOutputBuffers($startObLevel + 1, false);
    return ob_get_clean();
} 

If Response::closeOutputBuffers ' second argument is set to false it will call an "ob_end_clean" instead of "ob_end_flush" under the hood. The already rendered content is lost however.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM