ExceptionController.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\TwigBundle\Controller;
  11. use Symfony\Component\Debug\Exception\FlattenException;
  12. use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
  13. use Symfony\Component\HttpFoundation\Request;
  14. use Symfony\Component\HttpFoundation\Response;
  15. /**
  16. * ExceptionController renders error or exception pages for a given
  17. * FlattenException.
  18. *
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. * @author Matthias Pigulla <mp@webfactory.de>
  21. */
  22. class ExceptionController
  23. {
  24. protected $twig;
  25. /**
  26. * @var bool Show error (false) or exception (true) pages by default
  27. */
  28. protected $debug;
  29. public function __construct(\Twig_Environment $twig, $debug)
  30. {
  31. $this->twig = $twig;
  32. $this->debug = $debug;
  33. }
  34. /**
  35. * Converts an Exception to a Response.
  36. *
  37. * A "showException" request parameter can be used to force display of an error page (when set to false) or
  38. * the exception page (when true). If it is not present, the "debug" value passed into the constructor will
  39. * be used.
  40. *
  41. * @param Request $request The request
  42. * @param FlattenException $exception A FlattenException instance
  43. * @param DebugLoggerInterface $logger A DebugLoggerInterface instance
  44. *
  45. * @return Response
  46. *
  47. * @throws \InvalidArgumentException When the exception template does not exist
  48. */
  49. public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
  50. {
  51. $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
  52. $showException = $request->attributes->get('showException', $this->debug); // As opposed to an additional parameter, this maintains BC
  53. $code = $exception->getStatusCode();
  54. return new Response($this->twig->render(
  55. (string) $this->findTemplate($request, $request->getRequestFormat(), $code, $showException),
  56. array(
  57. 'status_code' => $code,
  58. 'status_text' => isset(Response::$statusTexts[$code]) ? Response::$statusTexts[$code] : '',
  59. 'exception' => $exception,
  60. 'logger' => $logger,
  61. 'currentContent' => $currentContent,
  62. )
  63. ));
  64. }
  65. /**
  66. * @param int $startObLevel
  67. *
  68. * @return string
  69. */
  70. protected function getAndCleanOutputBuffering($startObLevel)
  71. {
  72. if (ob_get_level() <= $startObLevel) {
  73. return '';
  74. }
  75. Response::closeOutputBuffers($startObLevel + 1, true);
  76. return ob_get_clean();
  77. }
  78. /**
  79. * @param Request $request
  80. * @param string $format
  81. * @param int $code An HTTP response status code
  82. * @param bool $showException
  83. *
  84. * @return string
  85. */
  86. protected function findTemplate(Request $request, $format, $code, $showException)
  87. {
  88. $name = $showException ? 'exception' : 'error';
  89. if ($showException && 'html' == $format) {
  90. $name = 'exception_full';
  91. }
  92. // For error pages, try to find a template for the specific HTTP status code and format
  93. if (!$showException) {
  94. $template = sprintf('@Twig/Exception/%s%s.%s.twig', $name, $code, $format);
  95. if ($this->templateExists($template)) {
  96. return $template;
  97. }
  98. }
  99. // try to find a template for the given format
  100. $template = sprintf('@Twig/Exception/%s.%s.twig', $name, $format);
  101. if ($this->templateExists($template)) {
  102. return $template;
  103. }
  104. // default to a generic HTML exception
  105. $request->setRequestFormat('html');
  106. return sprintf('@Twig/Exception/%s.html.twig', $showException ? 'exception_full' : $name);
  107. }
  108. // to be removed when the minimum required version of Twig is >= 3.0
  109. protected function templateExists($template)
  110. {
  111. $template = (string) $template;
  112. $loader = $this->twig->getLoader();
  113. if ($loader instanceof \Twig_ExistsLoaderInterface || method_exists($loader, 'exists')) {
  114. return $loader->exists($template);
  115. }
  116. try {
  117. $loader->getSourceContext($template)->getCode();
  118. return true;
  119. } catch (\Twig_Error_Loader $e) {
  120. }
  121. return false;
  122. }
  123. }