[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;
use Symfony\Bundle\FrameworkBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Debug\ExceptionFormatter;
use Symfony\Components\HttpFoundation\Request;
use Symfony\Components\HttpFoundation\Response;
use Symfony\Components\HttpKernel\Exception\HttpException;
use Symfony\Bundle\FrameworkBundle\Debug\ExceptionManager;
/*
* This file is part of the Symfony framework.
@ -27,60 +24,19 @@ class ExceptionController extends Controller
/**
* Converts an Exception to a Response.
*
* @param \Exception $exception An Exception instance
* @param Request $request The original Request instance
* @param array $logs An array of logs
* @param ExceptionManager $manager An ExceptionManager instance
*
* @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();
// when using CLI, we force the format to be TXT
if (0 === strncasecmp(PHP_SAPI, 'cli', 3)) {
$format = 'txt';
}
$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);
$response = $this->render(
'FrameworkBundle:Exception:'.($this['kernel']->isDebug() ? 'exception' : 'error'),
array('manager' => $manager)
);
$response->setStatusCode($manager->getStatusCode());
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
namespace Symfony\Bundle\FrameworkBundle\Controller;
namespace Symfony\Bundle\FrameworkBundle\Debug;
use Symfony\Components\DependencyInjection\ContainerInterface;
use Symfony\Components\EventDispatcher\EventDispatcher;
@ -28,12 +28,11 @@ class ExceptionListener
protected $controller;
protected $logger;
public function __construct(ContainerInterface $container, LoggerInterface $logger = null, $controller)
public function __construct(ContainerInterface $container, $controller, LoggerInterface $logger = null)
{
$this->container = $container;
$this->logger = $logger;
$this->controller = $controller;
$this->logger = $logger;
}
/**
@ -55,24 +54,21 @@ class ExceptionListener
$exception = $event->getParameter('exception');
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(
'_controller' => $this->controller,
'exception' => $exception,
'originalRequest' => $event->getParameter('request'),
'logs' => $this->container->has('zend.logger.writer.debug') ? $this->container->get('zend.logger.writer.debug')->getLogs() : array(),
$class = $this->container->getParameter('exception_manager.class');
$logger = $this->container->has('logger.debug') ? $this->container->get('logger.debug') : null;
$attributes = 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 {
$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) {
if (null !== $this->logger) {
$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.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.code.class">Symfony\Bundle\FrameworkBundle\Templating\Helper\CodeHelper</parameter>
<parameter key="templating.output_escaper">false</parameter>
<parameter key="templating.assets.version">null</parameter>
<parameter key="debug.file_link_format">null</parameter>
</parameters>
<services>
@ -86,6 +88,11 @@
<argument type="service" id="controller_resolver" />
</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" alias="templating.engine" />

View File

@ -9,8 +9,9 @@
<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="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_manager.class">Symfony\Bundle\FrameworkBundle\Debug\ExceptionManager</parameter>
<parameter key="esi.class">Symfony\Components\HttpKernel\Cache\Esi</parameter>
<parameter key="esi_listener.class">Symfony\Components\HttpKernel\Cache\EsiListener</parameter>
</parameters>
@ -47,8 +48,8 @@
<service id="exception_listener" class="%exception_listener.class%">
<tag name="kernel.listener" />
<argument type="service" id="service_container" />
<argument type="service" id="logger" on-invalid="null" />
<argument>%exception_listener.controller%</argument>
<argument type="service" id="logger" on-invalid="null" />
</service>
</services>
</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 $code.' '.$text."\n" ?>
*/
<?php echo $view->render('FrameworkBundle:Exception:error.js', array('manager' => $manager)) ?>

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(
'error' => array(
'code' => $code,
'message' => $text,
'code' => $manager->getStatusCode(),
'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" />
<div class="sfTMessageWrap">
<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>

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
=======================
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
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" ?>
<error code="<?php echo $code ?>" message="<?php echo $text ?>" />
<?php echo sprintf('<?xml version="1.0" encoding="%s" ?>', $view->getCharset())."\n" ?>
<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 $name."\n" ?>
<?php echo $message."\n" ?>
<?php foreach ($traces as $trace): ?>
<?php echo $trace."\n" ?>
<?php endforeach; ?>
<?php echo $view->render('FrameworkBundle:Exception:exception.txt', array('manager' => $manager)) ?>
*/

View File

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

View File

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

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">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $charset ?>"/>
<title><?php echo htmlspecialchars($message, ENT_QUOTES, $charset) ?> (<?php echo $code ?> <?php echo $text ?>)</title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $view->getCharset() ?>"/>
<title><?php echo htmlspecialchars($manager->getMessage(), ENT_QUOTES, $view->getCharset()) ?> (<?php echo $manager->getStatusCode() ?> <?php echo $manager->getStatusText() ?>)</title>
<style type="text/css">
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; }
<?php echo $view->render('FrameworkBundle:Exception:styles') ?>
</style>
<script type="text/javascript">
function toggle(id)
@ -44,8 +20,8 @@
<img src="data:image/png;base64,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" />
</div>
<div style="float: left; width: 600px">
<h2><?php echo $code ?> <?php echo $text ?> - <?php echo $name ?></h2>
<h1><?php echo str_replace("\n", '<br />', htmlspecialchars($message, ENT_QUOTES, $charset)) ?></h1>
<h2><?php echo $manager->getStatusCode() ?> <?php echo $manager->getStatusText() ?> - <?php echo $manager->getName() ?></h2>
<h1><?php echo str_replace("\n", '<br />', htmlspecialchars($manager->getMessage(), ENT_QUOTES, $view->getCharset())) ?></h1>
</div>
<div style="clear: both"></div>
@ -54,30 +30,23 @@
<div id="main">
<h3>
Logs <a href="#" onclick="toggle('logs'); return false;">...</a>
<?php if ($errors): ?>
<span class="error"><?php echo $errors ?> errors</span>
<?php if ($manager->countErrors()): ?>
<span class="error"><?php echo $manager->countErrors() ?> errors</span>
<?php endif; ?>
</h3>
<div id="logs" style="display: none">
<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>
<?php echo $view->render('FrameworkBundle:Exception:logs', array('logs' => $manager->getLogs())) ?>
</div>
<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>
<div id="content" style="display: none">
<?php echo $currentContent ?>
<?php echo $manager->getCurrentContent() ?>
</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]
<?php foreach ($traces as $line): ?>
<?php echo $line ?>
<?php foreach ($manager->getTraces() as $i => $trace): ?>
<?php echo $view->render('FrameworkBundle:Exception:trace.txt', array('i' => $i, 'trace' => $trace)) ?>
<?php endforeach; ?>
<?php endif; ?>
[symfony] v. <?php echo \Symfony\Framework\Kernel::VERSION ?> (symfony-project.org)
[PHP] v. <?php echo PHP_VERSION ?>

View File

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