[FrameworkBundle] refactored Exception management

This commit is contained in:
Fabien Potencier 2010-08-15 08:35:01 +02:00
parent 955fd40dd8
commit d5069fc594
28 changed files with 384 additions and 336 deletions

View File

@ -3,10 +3,7 @@
namespace Symfony\Bundle\FrameworkBundle\Controller; namespace Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Debug\ExceptionFormatter; use Symfony\Bundle\FrameworkBundle\Debug\ExceptionManager;
use Symfony\Components\HttpFoundation\Request;
use Symfony\Components\HttpFoundation\Response;
use Symfony\Components\HttpKernel\Exception\HttpException;
/* /*
* This file is part of the Symfony framework. * This file is part of the Symfony framework.
@ -27,60 +24,19 @@ class ExceptionController extends Controller
/** /**
* Converts an Exception to a Response. * Converts an Exception to a Response.
* *
* @param \Exception $exception An Exception instance * @param ExceptionManager $manager An ExceptionManager instance
* @param Request $request The original Request instance
* @param array $logs An array of logs
* *
* @throws \InvalidArgumentException When the exception template does not exist * @throws \InvalidArgumentException When the exception template does not exist
*/ */
public function exceptionAction(\Exception $exception, Request $originalRequest, array $logs) public function exceptionAction(ExceptionManager $manager)
{ {
$template = $this->container->getParameter('kernel.debug') ? 'exception' : 'error'; $this['request']->setRequestFormat($manager->getFormat());
$format = $format = $originalRequest->getRequestFormat(); $response = $this->render(
'FrameworkBundle:Exception:'.($this['kernel']->isDebug() ? 'exception' : 'error'),
// when using CLI, we force the format to be TXT array('manager' => $manager)
if (0 === strncasecmp(PHP_SAPI, 'cli', 3)) { );
$format = 'txt'; $response->setStatusCode($manager->getStatusCode());
}
$template = $this['templating']->getLoader()->load($template, array(
'bundle' => 'FrameworkBundle',
'controller' => 'Exception',
'format' => '.'.$format,
));
if (false === $template) {
throw new \InvalidArgumentException(sprintf('The exception template for format "%s" does not exist.', $format));
}
$code = $exception instanceof HttpException ? $exception->getCode() : 500;
$text = Response::$statusTexts[$code];
$formatter = new ExceptionFormatter($this->container->getParameterBag()->has('debug.file_link_format') ? $this->container->getParameter('debug.file_link_format') : null, $this->container->getParameter('kernel.charset'));
$message = null === $exception->getMessage() ? 'n/a' : $exception->getMessage();
$name = get_class($exception);
$traces = $formatter->getTraces($exception, 'html' === $format ? 'html' : 'text');
$charset = $this->container->getParameter('kernel.charset');
$errors = 0;
foreach ($logs as $log) {
if ('ERR' === $log['priorityName']) {
++$errors;
}
}
$currentContent = '';
while (false !== $content = ob_get_clean()) {
$currentContent .= $content;
}
ob_start();
require $template;
$content = ob_get_clean();
$response = $this['response'];
$response->setStatusCode($code);
$response->setContent($content);
return $response; return $response;
} }

View File

@ -1,179 +0,0 @@
<?php
namespace Symfony\Bundle\FrameworkBundle\Debug;
use Symfony\Components\DependencyInjection\ContainerInterface;
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* ExceptionFormatter.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class ExceptionFormatter
{
protected $fileLinkFormat;
protected $charset;
/**
* Constructor.
*
* @param string $fileLinkFormat The format for links to source files
* @param string $charset The current charset
*/
public function __construct($fileLinkFormat, $charset = 'UTF-8')
{
$this->fileLinkFormat = null !== $fileLinkFormat ? $fileLinkFormat : ini_get('xdebug.file_link_format');
$this->charset = $charset;
}
/**
* Returns an array of exception traces.
*
* @param Exception $exception An Exception implementation instance
* @param string $format The trace format (txt or html)
*
* @return array An array of traces
*/
public function getTraces(\Exception $exception, $format = 'txt')
{
$traceData = $exception->getTrace();
array_unshift($traceData, array(
'function' => '',
'file' => $exception->getFile() != null ? $exception->getFile() : null,
'line' => $exception->getLine() != null ? $exception->getLine() : null,
'args' => array(),
));
$traces = array();
if ($format == 'html') {
$lineFormat = 'at <strong>%s%s%s</strong>(%s)<br />in <em>%s</em> line %s <a href="#" onclick="toggle(\'%s\'); return false;">...</a><br /><ul class="code" id="%s" style="display: %s">%s</ul>';
} else {
$lineFormat = 'at %s%s%s(%s) in %s line %s';
}
for ($i = 0, $count = count($traceData); $i < $count; $i++) {
$line = isset($traceData[$i]['line']) ? $traceData[$i]['line'] : null;
$file = isset($traceData[$i]['file']) ? $traceData[$i]['file'] : null;
$args = isset($traceData[$i]['args']) ? $traceData[$i]['args'] : array();
$traces[] = sprintf($lineFormat,
(isset($traceData[$i]['class']) ? $traceData[$i]['class'] : ''),
(isset($traceData[$i]['type']) ? $traceData[$i]['type'] : ''),
$traceData[$i]['function'],
$this->formatArgs($args, false, $format),
$this->formatFile($file, $line, $format, null === $file ? 'n/a' : $file),
null === $line ? 'n/a' : $line,
'trace_'.$i,
'trace_'.$i,
$i == 0 ? 'block' : 'none',
$this->fileExcerpt($file, $line)
);
}
return $traces;
}
/**
* Returns an excerpt of a code file around the given line number.
*
* @param string $file A file path
* @param int $line The selected line number
*
* @return string An HTML string
*/
protected function fileExcerpt($file, $line)
{
if (is_readable($file)) {
$content = preg_split('#<br />#', highlight_file($file, true));
$lines = array();
for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++) {
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'>'.$content[$i - 1].'</li>';
}
return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
}
}
/**
* Formats an array as a string.
*
* @param array $args The argument array
* @param boolean $single
* @param string $format The format string (html or txt)
*
* @return string
*/
protected function formatArgs($args, $single = false, $format = 'html')
{
$result = array();
$single and $args = array($args);
foreach ($args as $key => $value) {
if (is_object($value)) {
$formattedValue = ($format == 'html' ? '<em>object</em>' : 'object').sprintf("('%s')", get_class($value));
} else if (is_array($value)) {
$formattedValue = ($format == 'html' ? '<em>array</em>' : 'array').sprintf("(%s)", $this->formatArgs($value));
} else if (is_string($value)) {
$formattedValue = ($format == 'html' ? sprintf("'%s'", $this->escape($value)) : "'$value'");
} else if (null === $value) {
$formattedValue = ($format == 'html' ? '<em>null</em>' : 'null');
} else {
$formattedValue = $value;
}
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escape($key), $formattedValue);
}
return implode(', ', $result);
}
/**
* Formats a file path.
*
* @param string $file An absolute file path
* @param integer $line The line number
* @param string $format The output format (txt or html)
* @param string $text Use this text for the link rather than the file path
*
* @return string
*/
protected function formatFile($file, $line, $format = 'html', $text = null)
{
if (null === $text) {
$text = $file;
}
if ('html' === $format && $file && $line && $this->fileLinkFormat) {
$link = strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line));
$text = sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', $link, $text);
}
return $text;
}
/**
* Escapes a string value with html entities
*
* @param string $value
*
* @return string
*/
protected function escape($value)
{
if (!is_string($value)) {
return $value;
}
return htmlspecialchars($value, ENT_QUOTES, $this->charset);
}
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace Symfony\Bundle\FrameworkBundle\Controller; namespace Symfony\Bundle\FrameworkBundle\Debug;
use Symfony\Components\DependencyInjection\ContainerInterface; use Symfony\Components\DependencyInjection\ContainerInterface;
use Symfony\Components\EventDispatcher\EventDispatcher; use Symfony\Components\EventDispatcher\EventDispatcher;
@ -28,12 +28,11 @@ class ExceptionListener
protected $controller; protected $controller;
protected $logger; protected $logger;
public function __construct(ContainerInterface $container, LoggerInterface $logger = null, $controller) public function __construct(ContainerInterface $container, $controller, LoggerInterface $logger = null)
{ {
$this->container = $container; $this->container = $container;
$this->logger = $logger;
$this->controller = $controller; $this->controller = $controller;
$this->logger = $logger;
} }
/** /**
@ -55,24 +54,21 @@ class ExceptionListener
$exception = $event->getParameter('exception'); $exception = $event->getParameter('exception');
if (null !== $this->logger) { if (null !== $this->logger) {
$this->logger->err(sprintf('%s (uncaught %s exception)', $exception->getMessage(), get_class($exception))); $this->logger->err(sprintf('%s: %s (uncaught exception)', get_class($exception), $exception->getMessage()));
} }
$parameters = array( $class = $this->container->getParameter('exception_manager.class');
'_controller' => $this->controller, $logger = $this->container->has('logger.debug') ? $this->container->get('logger.debug') : null;
'exception' => $exception,
'originalRequest' => $event->getParameter('request'), $attributes = array(
'logs' => $this->container->has('zend.logger.writer.debug') ? $this->container->get('zend.logger.writer.debug')->getLogs() : array(), '_controller' => $this->controller,
'manager' => new $class($exception, $event->getParameter('request'), $logger),
); );
$request = $event->getParameter('request')->duplicate(null, null, $parameters); $request = $event->getParameter('request')->duplicate(null, null, $attributes);
try { try {
$response = $event->getSubject()->handle($request, HttpKernelInterface::SUB_REQUEST, true); $response = $event->getSubject()->handle($request, HttpKernelInterface::SUB_REQUEST, true);
if (null !== $this->logger) {
$this->logger->err(sprintf('%s: %s', get_class($exception), $exception->getMessage()));
}
} catch (\Exception $e) { } catch (\Exception $e) {
if (null !== $this->logger) { if (null !== $this->logger) {
$this->logger->err(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage())); $this->logger->err(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage()));

View File

@ -0,0 +1,137 @@
<?php
namespace Symfony\Bundle\FrameworkBundle\Debug;
use Symfony\Components\DependencyInjection\ContainerInterface;
use Symfony\Components\HttpKernel\Exception\HttpException;
use Symfony\Components\HttpFoundation\Request;
use Symfony\Components\HttpFoundation\Response;
use Symfony\Components\HttpKernel\Log\DebugLoggerInterface;
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* ExceptionManager.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class ExceptionManager
{
protected $exception;
protected $request;
protected $logger;
protected $currentContent;
public function __construct(\Exception $exception, Request $request, DebugLoggerInterface $logger)
{
$this->exception = $exception;
$this->request = $request;
$this->logger = $logger;
$this->currentContent = '';
while (false !== $content = ob_get_clean()) {
$this->currentContent .= $content;
}
}
public function getException()
{
return $this->exception;
}
public function getCurrentContent()
{
return $this->currentContent;
}
public function getLogger()
{
return $this->logger;
}
public function getLogs()
{
return $this->logger->getLogs();
}
public function countErrors()
{
$errors = 0;
foreach ($this->logger->getLogs() as $log) {
if ('ERR' === $log['priorityName']) {
++$errors;
}
}
return $errors;
}
public function getFormat()
{
$format = $this->request->getRequestFormat();
// when using CLI, we force the format to be TXT
if (0 === strncasecmp(PHP_SAPI, 'cli', 3)) {
$format = 'txt';
}
return $format;
}
public function getStatusCode()
{
return $this->exception instanceof HttpException ? $this->exception->getCode() : 500;
}
public function getStatusText()
{
return Response::$statusTexts[$this->getStatusCode()];
}
public function getMessage()
{
return null === $this->exception->getMessage() ? 'n/a' : $this->exception->getMessage();
}
public function getName()
{
return get_class($this->exception);
}
/**
* Returns an array of exception traces.
*
* @return array An array of traces
*/
public function getTraces()
{
$traces = array();
$traces[] = array(
'class' => '',
'type' => '',
'function' => '',
'file' => $this->exception->getFile(),
'line' => $this->exception->getLine(),
'args' => array(),
);
foreach ($this->exception->getTrace() as $entry) {
$traces[] = array(
'class' => isset($entry['class']) ? $entry['class'] : '',
'type' => isset($entry['type']) ? $entry['type'] : '',
'function' => $entry['function'],
'file' => isset($entry['file']) ? $entry['file'] : null,
'line' => isset($entry['line']) ? $entry['line'] : null,
'args' => isset($entry['args']) ? $entry['args'] : array(),
);
}
return $traces;
}
}

View File

@ -17,8 +17,10 @@
<parameter key="templating.helper.router.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\RouterHelper</parameter> <parameter key="templating.helper.router.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\RouterHelper</parameter>
<parameter key="templating.helper.request.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\RequestHelper</parameter> <parameter key="templating.helper.request.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\RequestHelper</parameter>
<parameter key="templating.helper.session.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\SessionHelper</parameter> <parameter key="templating.helper.session.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\SessionHelper</parameter>
<parameter key="templating.helper.code.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\CodeHelper</parameter>
<parameter key="templating.output_escaper">false</parameter> <parameter key="templating.output_escaper">false</parameter>
<parameter key="templating.assets.version">null</parameter> <parameter key="templating.assets.version">null</parameter>
<parameter key="debug.file_link_format">null</parameter>
</parameters> </parameters>
<services> <services>
@ -86,6 +88,11 @@
<argument type="service" id="controller_resolver" /> <argument type="service" id="controller_resolver" />
</service> </service>
<service id="templating.helper.code" class="%templating.helper.code.class%">
<tag name="templating.helper" alias="code" />
<argument>%debug.file_link_format%</argument>
</service>
<service id="templating.loader" alias="templating.loader.filesystem" /> <service id="templating.loader" alias="templating.loader.filesystem" />
<service id="templating" alias="templating.engine" /> <service id="templating" alias="templating.engine" />

View File

@ -9,8 +9,9 @@
<parameter key="controller_resolver.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver</parameter> <parameter key="controller_resolver.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver</parameter>
<parameter key="controller_name_converter.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerNameConverter</parameter> <parameter key="controller_name_converter.class">Symfony\Bundle\FrameworkBundle\Controller\ControllerNameConverter</parameter>
<parameter key="response_listener.class">Symfony\Components\HttpKernel\ResponseListener</parameter> <parameter key="response_listener.class">Symfony\Components\HttpKernel\ResponseListener</parameter>
<parameter key="exception_listener.class">Symfony\Bundle\FrameworkBundle\Controller\ExceptionListener</parameter> <parameter key="exception_listener.class">Symfony\Bundle\FrameworkBundle\Debug\ExceptionListener</parameter>
<parameter key="exception_listener.controller">Symfony\Bundle\FrameworkBundle\Controller\ExceptionController::exceptionAction</parameter> <parameter key="exception_listener.controller">Symfony\Bundle\FrameworkBundle\Controller\ExceptionController::exceptionAction</parameter>
<parameter key="exception_manager.class">Symfony\Bundle\FrameworkBundle\Debug\ExceptionManager</parameter>
<parameter key="esi.class">Symfony\Components\HttpKernel\Cache\Esi</parameter> <parameter key="esi.class">Symfony\Components\HttpKernel\Cache\Esi</parameter>
<parameter key="esi_listener.class">Symfony\Components\HttpKernel\Cache\EsiListener</parameter> <parameter key="esi_listener.class">Symfony\Components\HttpKernel\Cache\EsiListener</parameter>
</parameters> </parameters>
@ -47,8 +48,8 @@
<service id="exception_listener" class="%exception_listener.class%"> <service id="exception_listener" class="%exception_listener.class%">
<tag name="kernel.listener" /> <tag name="kernel.listener" />
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
<argument type="service" id="logger" on-invalid="null" />
<argument>%exception_listener.controller%</argument> <argument>%exception_listener.controller%</argument>
<argument type="service" id="logger" on-invalid="null" />
</service> </service>
</services> </services>
</container> </container>

View File

@ -1 +1 @@
<?php include sfException::getTemplatePathForError('xml', false) ?> <?php echo $view->render('FrameworkBundle:Exception:error.xml', array('manager' => $manager)) ?>

View File

@ -1,3 +1 @@
/* <?php echo $view->render('FrameworkBundle:Exception:error.js', array('manager' => $manager)) ?>
<?php echo $code.' '.$text."\n" ?>
*/

View File

@ -1,3 +1,3 @@
/* /*
<?php echo $code.' '.$text."\n" ?> <?php echo $manager->getStatusCode().' '.$manager->getStatusText()."\n" ?>
*/ */

View File

@ -1,5 +1,5 @@
<?php echo json_encode(array( <?php echo json_encode(array(
'error' => array( 'error' => array(
'code' => $code, 'code' => $manager->getStatusCode(),
'message' => $text, 'message' => $manager->getStatusText(),
))) ?> ))) ?>

View File

@ -27,7 +27,7 @@
<img alt="page not found" class="sfTMessageIcon" src="<?php echo $path ?>/sf/sf_default/images/icons/tools48.png" height="48" width="48" /> <img alt="page not found" class="sfTMessageIcon" src="<?php echo $path ?>/sf/sf_default/images/icons/tools48.png" height="48" width="48" />
<div class="sfTMessageWrap"> <div class="sfTMessageWrap">
<h1>Oops! An Error Occurred</h1> <h1>Oops! An Error Occurred</h1>
<h5>The server returned a "<?php echo $code ?> <?php echo $text ?>".</h5> <h5>The server returned a "<?php echo $manager->getStatusCode() ?> <?php echo $manager->getStatusText() ?>".</h5>
</div> </div>
</div> </div>

View File

@ -1 +1 @@
<?php include sfException::getTemplatePathForError('xml', false) ?> <?php echo $view->render('FrameworkBundle:Exception:error.xml', array('manager' => $manager)) ?>

View File

@ -1,7 +1,7 @@
Oops! An Error Occurred Oops! An Error Occurred
======================= =======================
The server returned a "<?php echo $code ?> <?php echo $text ?>". The server returned a "<?php echo $manager->getStatusCode() ?> <?php echo $manager->getStatusText() ?>".
Please e-mail us at [email] and let us know what you were doing when this Please e-mail us at [email] and let us know what you were doing when this
error occurred. We will fix it as soon as possible. Sorry for any error occurred. We will fix it as soon as possible. Sorry for any

View File

@ -1,2 +1,2 @@
<?php echo sprintf('<?xml version="1.0" encoding="%s" ?>', $charset)."\n" ?> <?php echo sprintf('<?xml version="1.0" encoding="%s" ?>', $view->getCharset())."\n" ?>
<error code="<?php echo $code ?>" message="<?php echo $text ?>" /> <error code="<?php echo $manager->getStatusCode() ?>" message="<?php echo $manager->getStatusText() ?>" />

View File

@ -1 +1 @@
<?php include sfException::getTemplatePathForError('xml', true) ?> <?php echo $view->render('FrameworkBundle:Exception:exception.xml', array('manager' => $manager)) ?>

View File

@ -1,10 +1,3 @@
/* /*
<?php echo $code.' '.$text."\n" ?> <?php echo $view->render('FrameworkBundle:Exception:exception.txt', array('manager' => $manager)) ?>
<?php echo $name."\n" ?>
<?php echo $message."\n" ?>
<?php foreach ($traces as $trace): ?>
<?php echo $trace."\n" ?>
<?php endforeach; ?>
*/ */

View File

@ -1,10 +1,3 @@
/* /*
<?php echo $code.' '.$text."\n" ?> <?php echo $view->render('FrameworkBundle:Exception:exception.txt', array('manager' => $manager)) ?>
<?php echo $name."\n" ?>
<?php echo $message."\n" ?>
<?php foreach ($traces as $trace): ?>
<?php echo $trace."\n" ?>
<?php endforeach; ?>
*/ */

View File

@ -1,10 +1,9 @@
<?php echo json_encode(array( <?php echo json_encode(array(
'error' => array( 'error' => array(
'code' => $code, 'code' => $manager->getStatusCode(),
'message' => $message, 'message' => $manager->getMessage(),
'debug' => array( 'debug' => array(
'name' => $name, 'name' => $manager->getName(),
'message' => $message, 'traces' => $manager->getTraces(),
'traces' => $traces,
), ),
))) ?> ))) ?>

View File

@ -1,34 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $charset ?>"/> <meta http-equiv="Content-Type" content="text/html; charset=<?php echo $view->getCharset() ?>"/>
<title><?php echo htmlspecialchars($message, ENT_QUOTES, $charset) ?> (<?php echo $code ?> <?php echo $text ?>)</title> <title><?php echo htmlspecialchars($manager->getMessage(), ENT_QUOTES, $view->getCharset()) ?> (<?php echo $manager->getStatusCode() ?> <?php echo $manager->getStatusText() ?>)</title>
<style type="text/css"> <style type="text/css">
body { margin: 0; padding: 0; margin-top: 30px; background-color: #eee } <?php echo $view->render('FrameworkBundle:Exception:styles') ?>
body, td, th { font: 11px Verdana, Arial, sans-serif; color: #333 }
a { color: #333 }
h1 { margin: 0; margin-top: 4px; font-weight: normal; font-size: 170%; letter-spacing: -0.03em; }
h2 { margin: 0; padding: 0; font-size: 90%; font-weight: normal; letter-spacing: -0.02em; }
h3 { margin: 0; padding: 0; margin-bottom: 10px; font-size: 110% }
ul { padding-left: 20px; list-style: decimal }
ul li { padding-bottom: 5px; margin: 0 }
ol { font-family: monospace; white-space: pre; list-style-position: inside; margin: 0; padding: 10px 0 }
ol li { margin: -5px; padding: 0 }
ol .selected { font-weight: bold; background-color: #ffd; padding: 2px 0 }
table.vars { padding: 0; margin: 0; border: 1px solid #999; background-color: #fff; }
table.vars th { padding: 2px; background-color: #ddd; font-weight: bold }
table.vars td { padding: 2px; font-family: monospace; white-space: pre }
p.error { padding: 10px; background-color: #f00; font-weight: bold; text-align: center; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; }
p.error a { color: #fff }
#main { padding: 20px 25px; margin: 0; margin-bottom: 20px; border: 1px solid #ddd; background-color: #fff; text-align:left; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; min-width: 770px; max-width: 770px }
#message { padding: 20px 25px; margin: 0; margin-bottom: 5px; border: 1px solid #ddd; text-align:left; background-color: #c8e8f3; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; min-width: 770px; max-width: 770px }
#content { border: 1px solid #ddd; margin-top: 10px; padding: 7px; overflow: auto; }
a.file_link { text-decoration: none; }
a.file_link:hover { text-decoration: underline; }
.code { overflow: auto; }
img { vertical-align: middle; }
a img { border: 0; }
.error { background-color: #f66; padding: 1px 3px; color: #111; }
</style> </style>
<script type="text/javascript"> <script type="text/javascript">
function toggle(id) function toggle(id)
@ -44,8 +20,8 @@
<img src="data:image/png;base64,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" /> <img src="data:image/png;base64,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" />
</div> </div>
<div style="float: left; width: 600px"> <div style="float: left; width: 600px">
<h2><?php echo $code ?> <?php echo $text ?> - <?php echo $name ?></h2> <h2><?php echo $manager->getStatusCode() ?> <?php echo $manager->getStatusText() ?> - <?php echo $manager->getName() ?></h2>
<h1><?php echo str_replace("\n", '<br />', htmlspecialchars($message, ENT_QUOTES, $charset)) ?></h1> <h1><?php echo str_replace("\n", '<br />', htmlspecialchars($manager->getMessage(), ENT_QUOTES, $view->getCharset())) ?></h1>
</div> </div>
<div style="clear: both"></div> <div style="clear: both"></div>
@ -54,30 +30,23 @@
<div id="main"> <div id="main">
<h3> <h3>
Logs <a href="#" onclick="toggle('logs'); return false;">...</a> Logs <a href="#" onclick="toggle('logs'); return false;">...</a>
<?php if ($errors): ?> <?php if ($manager->countErrors()): ?>
<span class="error"><?php echo $errors ?> errors</span> <span class="error"><?php echo $manager->countErrors() ?> errors</span>
<?php endif; ?> <?php endif; ?>
</h3> </h3>
<div id="logs" style="display: none"> <div id="logs" style="display: none">
<ul> <?php echo $view->render('FrameworkBundle:Exception:logs', array('logs' => $manager->getLogs())) ?>
<?php foreach ($logs as $log): ?>
<li<?php if ('ERR' === $log['priorityName']): ?> class="error"<?php endif; ?>>
<?php echo $log['priorityName'] ?>:
<?php echo $log['message'] ?>
</li>
<?php endforeach; ?>
</ul>
</div> </div>
<h3>Stack Trace</h3> <h3>Stack Trace</h3>
<ul><li><?php echo implode('</li><li>', $traces) ?></li></ul> <?php echo $view->render('FrameworkBundle:Exception:traces', array('traces' => $manager->getTraces())) ?>
<h3>Content of the Output <a href="#" onclick="toggle('content'); return false;">...</a></h3> <h3>Content of the Output <a href="#" onclick="toggle('content'); return false;">...</a></h3>
<div id="content" style="display: none"> <div id="content" style="display: none">
<?php echo $currentContent ?> <?php echo $manager->getCurrentContent() ?>
</div> </div>
<div style="clear: both"></div> <div style="clear: both"></div>

View File

@ -1 +1 @@
<?php include sfException::getTemplatePathForError('xml', true) ?> <?php echo $view->render('FrameworkBundle:Exception:exception.xml', array('manager' => $manager)) ?>

View File

@ -1,13 +1,14 @@
[exception] <?php echo $code.' | '.$text.' | '.$name ?> [exception] <?php echo $manager->getStatusCode().' | '.$manager->getStatusText().' | '.$manager->getName() ?>
[message] <?php echo $message ?> [message] <?php echo $manager->getMessage() ?>
<?php if (isset($traces) && count($traces) > 0): ?> <?php if (count($manager->getTraces())): ?>
[stack trace] [stack trace]
<?php foreach ($traces as $line): ?> <?php foreach ($manager->getTraces() as $i => $trace): ?>
<?php echo $line ?> <?php echo $view->render('FrameworkBundle:Exception:trace.txt', array('i' => $i, 'trace' => $trace)) ?>
<?php endforeach; ?> <?php endforeach; ?>
<?php endif; ?> <?php endif; ?>
[symfony] v. <?php echo \Symfony\Framework\Kernel::VERSION ?> (symfony-project.org) [symfony] v. <?php echo \Symfony\Framework\Kernel::VERSION ?> (symfony-project.org)
[PHP] v. <?php echo PHP_VERSION ?> [PHP] v. <?php echo PHP_VERSION ?>

View File

@ -1,11 +1,14 @@
<?php echo sprintf('<?xml version="1.0" encoding="%s" ?>', $charset)."\n" ?> <?php echo sprintf('<?xml version="1.0" encoding="%s" ?>', $view->getCharset())."\n" ?>
<error code="<?php echo $code ?>" message="<?php echo $text ?>"> <error code="<?php echo $manager->getStatusCode() ?>" message="<?php echo $manager->getStatusText() ?>">
<debug> <debug>
<name><?php echo $name ?></name> <name><?php echo $manager->getName() ?></name>
<message><?php echo htmlspecialchars($message, ENT_QUOTES, $charset) ?></message> <message><?php echo htmlspecialchars($manager->getMessage(), ENT_QUOTES, $view->getCharset()) ?></message>
<traces> <traces>
<?php foreach ($traces as $trace): ?> <?php foreach ($manager->getTraces() as $i => $trace): ?>
<trace><?php echo $trace ?></trace> <trace>
<?php echo $view->render('FrameworkBundle:Exception:trace.txt', array('i' => $i, 'trace' => $trace)) ?>
</trace>
<?php endforeach; ?> <?php endforeach; ?>
</traces> </traces>
</debug> </debug>

View File

@ -0,0 +1,8 @@
<ul>
<?php foreach ($logs as $log): ?>
<li<?php if ('ERR' === $log['priorityName']): ?> class="error"<?php endif; ?>>
<?php echo $log['priorityName'] ?>:
<?php echo $log['message'] ?>
</li>
<?php endforeach; ?>
</ul>

View File

@ -0,0 +1,25 @@
body { margin: 0; padding: 0; margin-top: 30px; background-color: #eee }
body, td, th { font: 11px Verdana, Arial, sans-serif; color: #333 }
a { color: #333 }
h1 { margin: 0; margin-top: 4px; font-weight: normal; font-size: 170%; letter-spacing: -0.03em; }
h2 { margin: 0; padding: 0; font-size: 90%; font-weight: normal; letter-spacing: -0.02em; }
h3 { margin: 0; padding: 0; margin-bottom: 10px; font-size: 110% }
ul { padding-left: 20px; list-style: decimal }
ul li { padding-bottom: 5px; margin: 0 }
ol { font-family: monospace; white-space: pre; list-style-position: inside; margin: 0; padding: 10px 0 }
ol li { margin: -5px; padding: 0 }
ol .selected { font-weight: bold; background-color: #ffd; padding: 2px 0 }
table.vars { padding: 0; margin: 0; border: 1px solid #999; background-color: #fff; }
table.vars th { padding: 2px; background-color: #ddd; font-weight: bold }
table.vars td { padding: 2px; font-family: monospace; white-space: pre }
p.error { padding: 10px; background-color: #f00; font-weight: bold; text-align: center; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; }
p.error a { color: #fff }
#main { padding: 20px 25px; margin: 0; margin-bottom: 20px; border: 1px solid #ddd; background-color: #fff; text-align:left; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; min-width: 770px; max-width: 770px }
#message { padding: 20px 25px; margin: 0; margin-bottom: 5px; border: 1px solid #ddd; text-align:left; background-color: #c8e8f3; -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; min-width: 770px; max-width: 770px }
#content { border: 1px solid #ddd; margin-top: 10px; padding: 7px; overflow: auto; }
a.file_link { text-decoration: none; }
a.file_link:hover { text-decoration: underline; }
.code { overflow: auto; }
img { vertical-align: middle; }
a img { border: 0; }
.error { background-color: #f66; padding: 1px 3px; color: #111; }

View File

@ -0,0 +1,10 @@
<?php if ($trace['function']): ?>
at <strong><?php echo $trace['class'] ?><?php echo $trace['type'] ?><?php echo $trace['function'] ?></strong>(<?php echo $view->code->formatArgs($trace['args']) ?>)<br />
<?php endif; ?>
<?php if ($trace['file'] && $trace['line']): ?>
in <em><?php echo $view->code->formatFile($trace['file'], $trace['line']) ?></em> line <?php echo $trace['line'] ?>
<a href="#" onclick="toggle('trace_<?php echo $i ?>'); return false;">...</a><br />
<ul class="code" id="trace_<?php echo $i ?>" style="display: <?php echo 0 === $i ? 'block' : 'none' ?>">
<?php echo $view->code->fileExcerpt($trace['file'], $trace['line']) ?>
</ul>
<?php endif; ?>

View File

@ -0,0 +1,8 @@
<?php if ($trace['function']): ?>
at <?php echo $trace['class'].$trace['type'].$trace['function'] ?>(<?php echo $view->code->formatArgs($trace['args']) ?>)
<?php else: ?>
at n/a
<?php endif; ?>
<?php if ($trace['file'] && $trace['line']): ?>
in <?php echo $trace['file'] ?> line <?php echo $trace['line'] ?>
<?php endif; ?>

View File

@ -0,0 +1,7 @@
<ul>
<?php foreach ($traces as $i => $trace): ?>
<li>
<?php echo $view->render('FrameworkBundle:Exception:trace', array('i' => $i, 'trace' => $trace)) ?>
</li>
<?php endforeach; ?>
</ul>

View File

@ -0,0 +1,116 @@
<?php
namespace Symfony\Bundle\FrameworkBundle\Templating\Helper;
use Symfony\Components\Templating\Helper\Helper;
/*
* This file is part of the Symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* CodeHelper.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
*/
class CodeHelper extends Helper
{
protected $fileLinkFormat;
/**
* Constructor.
*
* @param string $fileLinkFormat The format for links to source files
*/
public function __construct($fileLinkFormat)
{
$this->fileLinkFormat = null !== $fileLinkFormat ? $fileLinkFormat : ini_get('xdebug.file_link_format');
}
/**
* Formats an array as a string.
*
* @param array $args The argument array
*
* @return string
*/
public function formatArgs($args)
{
$result = array();
foreach ($args as $key => $value) {
if (is_object($value)) {
$formattedValue = sprintf("object('%s')", get_class($value));
} elseif (is_array($value)) {
$formattedValue = sprintf("array(%s)", $this->formatArgs($value));
} elseif (is_string($value)) {
$formattedValue = sprintf("'%s'", $value);
} elseif (null === $value) {
$formattedValue = 'null';
} else {
$formattedValue = $value;
}
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
}
return implode(', ', $result);
}
/**
* Returns an excerpt of a code file around the given line number.
*
* @param string $file A file path
* @param int $line The selected line number
*
* @return string An HTML string
*/
public function fileExcerpt($file, $line)
{
if (is_readable($file)) {
$content = preg_split('#<br />#', highlight_file($file, true));
$lines = array();
for ($i = max($line - 3, 1), $max = min($line + 3, count($content)); $i <= $max; $i++) {
$lines[] = '<li'.($i == $line ? ' class="selected"' : '').'>'.$content[$i - 1].'</li>';
}
return '<ol start="'.max($line - 3, 1).'">'.implode("\n", $lines).'</ol>';
}
}
/**
* Formats a file path.
*
* @param string $file An absolute file path
* @param integer $line The line number
* @param string $format The output format (txt or html)
* @param string $text Use this text for the link rather than the file path
*
* @return string
*/
public function formatFile($file, $line)
{
if (!$this->fileLinkFormat) {
return $file;
}
$link = strtr($this->fileLinkFormat, array('%f' => $file, '%l' => $line));
return sprintf('<a href="%s" title="Click to open this file" class="file_link">%s</a>', $link, $file);
}
/**
* Returns the canonical name of this helper.
*
* @return string The canonical name
*/
public function getName()
{
return 'code';
}
}