Issue #2157691 by damiankloip: Move some helper methods in errors.inc to an Error utility class.
parent
77456421b8
commit
4f66a53b4f
|
@ -11,6 +11,7 @@ use Drupal\Core\DrupalKernel;
|
|||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Utility\Title;
|
||||
use Drupal\Core\Utility\Error;
|
||||
use Symfony\Component\ClassLoader\ApcClassLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
|
@ -1456,7 +1457,7 @@ function request_uri($omit_query_string = FALSE) {
|
|||
* A link to associate with the message.
|
||||
*
|
||||
* @see watchdog()
|
||||
* @see _drupal_decode_exception()
|
||||
* @see \Drupal\Core\Utility\Error::decodeException()
|
||||
*/
|
||||
function watchdog_exception($type, Exception $exception, $message = NULL, $variables = array(), $severity = WATCHDOG_ERROR, $link = NULL) {
|
||||
|
||||
|
@ -1464,7 +1465,7 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia
|
|||
if (empty($message)) {
|
||||
// The exception message is run through
|
||||
// \Drupal\Component\Utility\String::checkPlain() by
|
||||
// _drupal_decode_exception().
|
||||
// \Drupal\Core\Utility\Error:decodeException().
|
||||
$message = '%type: !message in %function (line %line of %file).';
|
||||
}
|
||||
// $variables must be an array so that we can add the exception information.
|
||||
|
@ -1472,8 +1473,7 @@ function watchdog_exception($type, Exception $exception, $message = NULL, $varia
|
|||
$variables = array();
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/errors.inc';
|
||||
$variables += _drupal_decode_exception($exception);
|
||||
$variables += Error::decodeException($exception);
|
||||
watchdog($type, $message, $variables, $severity, $link);
|
||||
}
|
||||
|
||||
|
@ -1934,15 +1934,15 @@ function _drupal_exception_handler($exception) {
|
|||
|
||||
try {
|
||||
// Log the message to the watchdog and return an error page to the user.
|
||||
_drupal_log_error(_drupal_decode_exception($exception), TRUE);
|
||||
_drupal_log_error(Error::decodeException($exception), TRUE);
|
||||
}
|
||||
catch (Exception $exception2) {
|
||||
// Another uncaught exception was thrown while handling the first one.
|
||||
// If we are displaying errors, then do so with no possibility of a further uncaught exception being thrown.
|
||||
if (error_displayable()) {
|
||||
print '<h1>Additional uncaught exception thrown while handling exception.</h1>';
|
||||
print '<h2>Original</h2><p>' . _drupal_render_exception_safe($exception) . '</p>';
|
||||
print '<h2>Additional</h2><p>' . _drupal_render_exception_safe($exception2) . '</p><hr />';
|
||||
print '<h2>Original</h2><p>' . Error::renderExceptionSafe($exception) . '</p>';
|
||||
print '<h2>Additional</h2><p>' . Error::renderExceptionSafe($exception2) . '</p><hr />';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2977,7 +2977,7 @@ function _drupal_shutdown_function() {
|
|||
require_once __DIR__ . '/errors.inc';
|
||||
if (error_displayable()) {
|
||||
print '<h1>Uncaught exception thrown in shutdown function.</h1>';
|
||||
print '<p>' . _drupal_render_exception_safe($exception) . '</p><hr />';
|
||||
print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />';
|
||||
}
|
||||
error_log($exception);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Functions for error handling.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Utility\Error;
|
||||
use Drupal\Component\Utility\String;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
@ -58,7 +59,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line, $c
|
|||
$types = drupal_error_levels();
|
||||
list($severity_msg, $severity_level) = $types[$error_level];
|
||||
$backtrace = debug_backtrace();
|
||||
$caller = _drupal_get_last_caller($backtrace);
|
||||
$caller = Error::getLastCaller($backtrace);
|
||||
|
||||
if (!function_exists('filter_xss_admin')) {
|
||||
require_once __DIR__ . '/common.inc';
|
||||
|
@ -79,69 +80,6 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line, $c
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an exception and retrieves the correct caller.
|
||||
*
|
||||
* @param $exception
|
||||
* The exception object that was thrown.
|
||||
*
|
||||
* @return
|
||||
* An error in the format expected by _drupal_log_error().
|
||||
*/
|
||||
function _drupal_decode_exception($exception) {
|
||||
$message = $exception->getMessage();
|
||||
|
||||
$backtrace = $exception->getTrace();
|
||||
// Add the line throwing the exception to the backtrace.
|
||||
array_unshift($backtrace, array('line' => $exception->getLine(), 'file' => $exception->getFile()));
|
||||
|
||||
// For PDOException errors, we try to return the initial caller,
|
||||
// skipping internal functions of the database layer.
|
||||
if ($exception instanceof PDOException) {
|
||||
// The first element in the stack is the call, the second element gives us the caller.
|
||||
// We skip calls that occurred in one of the classes of the database layer
|
||||
// or in one of its global functions.
|
||||
$db_functions = array('db_query', 'db_query_range');
|
||||
while (!empty($backtrace[1]) && ($caller = $backtrace[1]) &&
|
||||
((isset($caller['class']) && (strpos($caller['class'], 'Query') !== FALSE || strpos($caller['class'], 'Database') !== FALSE || strpos($caller['class'], 'PDO') !== FALSE)) ||
|
||||
in_array($caller['function'], $db_functions))) {
|
||||
// We remove that call.
|
||||
array_shift($backtrace);
|
||||
}
|
||||
if (isset($exception->query_string, $exception->args)) {
|
||||
$message .= ": " . $exception->query_string . "; " . print_r($exception->args, TRUE);
|
||||
}
|
||||
}
|
||||
$caller = _drupal_get_last_caller($backtrace);
|
||||
|
||||
return array(
|
||||
'%type' => get_class($exception),
|
||||
// The standard PHP exception handler considers that the exception message
|
||||
// is plain-text. We mimick this behavior here.
|
||||
'!message' => String::checkPlain($message),
|
||||
'%function' => $caller['function'],
|
||||
'%file' => $caller['file'],
|
||||
'%line' => $caller['line'],
|
||||
'severity_level' => WATCHDOG_ERROR,
|
||||
'backtrace' => $backtrace,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an exception error message without further exceptions.
|
||||
*
|
||||
* @param $exception
|
||||
* The exception object that was thrown.
|
||||
*
|
||||
* @return
|
||||
* An error message.
|
||||
*/
|
||||
function _drupal_render_exception_safe($exception) {
|
||||
$decode = _drupal_decode_exception($exception);
|
||||
unset($decode['backtrace']);
|
||||
return String::checkPlain(strtr('%type: !message in %function (line %line of %file).', $decode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an error should be displayed.
|
||||
*
|
||||
|
@ -312,43 +250,6 @@ function _drupal_get_error_level() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last caller from a backtrace.
|
||||
*
|
||||
* @param $backtrace
|
||||
* A standard PHP backtrace. Passed by reference.
|
||||
*
|
||||
* @return
|
||||
* An associative array with keys 'file', 'line' and 'function'.
|
||||
*/
|
||||
function _drupal_get_last_caller(&$backtrace) {
|
||||
// Errors that occur inside PHP internal functions do not generate
|
||||
// information about file and line. Ignore black listed functions.
|
||||
$blacklist = array('debug', '_drupal_error_handler', '_drupal_exception_handler');
|
||||
while (($backtrace && !isset($backtrace[0]['line'])) ||
|
||||
(isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], $blacklist))) {
|
||||
array_shift($backtrace);
|
||||
}
|
||||
|
||||
// The first trace is the call itself.
|
||||
// It gives us the line and the file of the last call.
|
||||
$call = $backtrace[0];
|
||||
|
||||
// The second call give us the function where the call originated.
|
||||
if (isset($backtrace[1])) {
|
||||
if (isset($backtrace[1]['class'])) {
|
||||
$call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()';
|
||||
}
|
||||
else {
|
||||
$call['function'] = $backtrace[1]['function'] . '()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$call['function'] = 'main()';
|
||||
}
|
||||
return $call;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a backtrace into a plain-text string.
|
||||
*
|
||||
|
@ -359,31 +260,9 @@ function _drupal_get_last_caller(&$backtrace) {
|
|||
*
|
||||
* @return string
|
||||
* A plain-text line-wrapped string ready to be put inside <pre>.
|
||||
*
|
||||
* @deprecated Use \Drupal\Core\Utility\Error::formatBacktrace() instead.
|
||||
*/
|
||||
function format_backtrace(array $backtrace) {
|
||||
$return = '';
|
||||
foreach ($backtrace as $trace) {
|
||||
$call = array('function' => '', 'args' => array());
|
||||
if (isset($trace['class'])) {
|
||||
$call['function'] = $trace['class'] . $trace['type'] . $trace['function'];
|
||||
}
|
||||
elseif (isset($trace['function'])) {
|
||||
$call['function'] = $trace['function'];
|
||||
}
|
||||
else {
|
||||
$call['function'] = 'main';
|
||||
}
|
||||
if (isset($trace['args'])) {
|
||||
foreach ($trace['args'] as $arg) {
|
||||
if (is_scalar($arg)) {
|
||||
$call['args'][] = is_string($arg) ? '\'' . filter_xss($arg) . '\'' : $arg;
|
||||
}
|
||||
else {
|
||||
$call['args'][] = ucfirst(gettype($arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
$return .= $call['function'] . '(' . implode(', ', $call['args']) . ")\n";
|
||||
}
|
||||
return $return;
|
||||
return Error::formatBacktrace($backtrace);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
*/
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
|
||||
use Drupal\Core\Session\UserSession;
|
||||
use Drupal\Core\Utility\Error;
|
||||
|
||||
/**
|
||||
* Session handler assigned by session_set_save_handler().
|
||||
|
@ -228,7 +228,7 @@ function _drupal_session_write($sid, $value) {
|
|||
// uncaught exception being thrown.
|
||||
if (error_displayable()) {
|
||||
print '<h1>Uncaught exception thrown in session handler.</h1>';
|
||||
print '<p>' . _drupal_render_exception_safe($exception) . '</p><hr />';
|
||||
print '<p>' . Error::renderExceptionSafe($exception) . '</p><hr />';
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use Drupal\Component\Utility\String;
|
|||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Config\ConfigException;
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Utility\Error;
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -815,12 +816,11 @@ function update_do_one($module, $number, $dependency_map, &$context) {
|
|||
catch (Exception $e) {
|
||||
watchdog_exception('update', $e);
|
||||
|
||||
require_once __DIR__ . '/errors.inc';
|
||||
$variables = _drupal_decode_exception($e);
|
||||
$variables = Error::decodeException($e);
|
||||
unset($variables['backtrace']);
|
||||
// The exception message is run through
|
||||
// \Drupal\Component\Utility\String::checkPlain() by
|
||||
// _drupal_decode_exception().
|
||||
// \Drupal\Core\Utility\Error::decodeException().
|
||||
$ret['#abort'] = array('success' => FALSE, 'query' => t('%type: !message in %function (line %line of %file).', $variables));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
|
|||
use Drupal\Component\Utility\String;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Drupal\Core\ContentNegotiation;
|
||||
use Drupal\Core\Utility\Error;
|
||||
|
||||
/**
|
||||
* This controller handles HTTP errors generated by the routing system.
|
||||
|
@ -413,7 +414,8 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn
|
|||
array_shift($backtrace);
|
||||
}
|
||||
}
|
||||
$caller = $this->getLastCaller($backtrace);
|
||||
|
||||
$caller = Error::getLastCaller($backtrace);
|
||||
|
||||
return array(
|
||||
'%type' => $exception->getClass(),
|
||||
|
@ -427,46 +429,4 @@ class ExceptionController extends HtmlControllerBase implements ContainerAwareIn
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last caller from a backtrace.
|
||||
*
|
||||
* The last caller is not necessarily the first item in the backtrace. Rather,
|
||||
* it is the first item in the backtrace that is a PHP userspace function,
|
||||
* and not one of our debug functions.
|
||||
*
|
||||
* @param $backtrace
|
||||
* A standard PHP backtrace.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with keys 'file', 'line' and 'function'.
|
||||
*/
|
||||
protected function getLastCaller($backtrace) {
|
||||
// Ignore black listed error handling functions.
|
||||
$blacklist = array('debug', '_drupal_error_handler', '_drupal_exception_handler');
|
||||
|
||||
// Errors that occur inside PHP internal functions do not generate
|
||||
// information about file and line.
|
||||
while (($backtrace && !isset($backtrace[0]['line'])) ||
|
||||
(isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], $blacklist))) {
|
||||
array_shift($backtrace);
|
||||
}
|
||||
|
||||
// The first trace is the call itself.
|
||||
// It gives us the line and the file of the last call.
|
||||
$call = $backtrace[0];
|
||||
|
||||
// The second call give us the function where the call originated.
|
||||
if (isset($backtrace[1])) {
|
||||
if (isset($backtrace[1]['class'])) {
|
||||
$call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()';
|
||||
}
|
||||
else {
|
||||
$call['function'] = $backtrace[1]['function'] . '()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$call['function'] = 'main()';
|
||||
}
|
||||
return $call;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Utility\Error.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Utility;
|
||||
|
||||
use Drupal\Component\Utility\String;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
|
||||
/**
|
||||
* Drupal error utility class.
|
||||
*/
|
||||
class Error {
|
||||
|
||||
/**
|
||||
* The error severity level.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const ERROR = 3;
|
||||
|
||||
/**
|
||||
* An array of blacklisted functions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $blacklistFunctions = array('debug', '_drupal_error_handler', '_drupal_exception_handler');
|
||||
|
||||
/**
|
||||
* Decodes an exception and retrieves the correct caller.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* The exception object that was thrown.
|
||||
*
|
||||
* @return array
|
||||
* An error in the format expected by _drupal_log_error().
|
||||
*/
|
||||
public static function decodeException(\Exception $exception) {
|
||||
$message = $exception->getMessage();
|
||||
|
||||
$backtrace = $exception->getTrace();
|
||||
// Add the line throwing the exception to the backtrace.
|
||||
array_unshift($backtrace, array('line' => $exception->getLine(), 'file' => $exception->getFile()));
|
||||
|
||||
// For PDOException errors, we try to return the initial caller,
|
||||
// skipping internal functions of the database layer.
|
||||
if ($exception instanceof \PDOException) {
|
||||
// The first element in the stack is the call, the second element gives us
|
||||
// the caller. We skip calls that occurred in one of the classes of the
|
||||
// database layer or in one of its global functions.
|
||||
$db_functions = array('db_query', 'db_query_range');
|
||||
while (!empty($backtrace[1]) && ($caller = $backtrace[1]) &&
|
||||
((isset($caller['class']) && (strpos($caller['class'], 'Query') !== FALSE || strpos($caller['class'], 'Database') !== FALSE || strpos($caller['class'], 'PDO') !== FALSE)) ||
|
||||
in_array($caller['function'], $db_functions))) {
|
||||
// We remove that call.
|
||||
array_shift($backtrace);
|
||||
}
|
||||
if (isset($exception->query_string, $exception->args)) {
|
||||
$message .= ": " . $exception->query_string . "; " . print_r($exception->args, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
$caller = static::getLastCaller($backtrace);
|
||||
|
||||
return array(
|
||||
'%type' => get_class($exception),
|
||||
// The standard PHP exception handler considers that the exception message
|
||||
// is plain-text. We mimic this behavior here.
|
||||
'!message' => String::checkPlain($message),
|
||||
'%function' => $caller['function'],
|
||||
'%file' => $caller['file'],
|
||||
'%line' => $caller['line'],
|
||||
'severity_level' => static::ERROR,
|
||||
'backtrace' => $backtrace,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an exception error message without further exceptions.
|
||||
*
|
||||
* @param \Exception $exception
|
||||
* The exception object that was thrown.
|
||||
*
|
||||
* @return string
|
||||
* An error message.
|
||||
*/
|
||||
public static function renderExceptionSafe(\Exception $exception) {
|
||||
$decode = static::decodeException($exception);
|
||||
unset($decode['backtrace']);
|
||||
|
||||
return String::format('%type: !message in %function (line %line of %file).', $decode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last caller from a backtrace.
|
||||
*
|
||||
* @param array $backtrace
|
||||
* A standard PHP backtrace. Passed by reference.
|
||||
*
|
||||
* @return array
|
||||
* An associative array with keys 'file', 'line' and 'function'.
|
||||
*/
|
||||
public static function getLastCaller(array &$backtrace) {
|
||||
// Errors that occur inside PHP internal functions do not generate
|
||||
// information about file and line. Ignore black listed functions.
|
||||
while (($backtrace && !isset($backtrace[0]['line'])) ||
|
||||
(isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], static::$blacklistFunctions))) {
|
||||
array_shift($backtrace);
|
||||
}
|
||||
|
||||
// The first trace is the call itself.
|
||||
// It gives us the line and the file of the last call.
|
||||
$call = $backtrace[0];
|
||||
|
||||
// The second call gives us the function where the call originated.
|
||||
if (isset($backtrace[1])) {
|
||||
if (isset($backtrace[1]['class'])) {
|
||||
$call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()';
|
||||
}
|
||||
else {
|
||||
$call['function'] = $backtrace[1]['function'] . '()';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$call['function'] = 'main()';
|
||||
}
|
||||
|
||||
return $call;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a backtrace into a plain-text string.
|
||||
*
|
||||
* The calls show values for scalar arguments and type names for complex ones.
|
||||
*
|
||||
* @param array $backtrace
|
||||
* A standard PHP backtrace.
|
||||
*
|
||||
* @return string
|
||||
* A plain-text line-wrapped string ready to be put inside <pre>.
|
||||
*/
|
||||
public static function formatBacktrace(array $backtrace) {
|
||||
$return = '';
|
||||
|
||||
foreach ($backtrace as $trace) {
|
||||
$call = array('function' => '', 'args' => array());
|
||||
|
||||
if (isset($trace['class'])) {
|
||||
$call['function'] = $trace['class'] . $trace['type'] . $trace['function'];
|
||||
}
|
||||
elseif (isset($trace['function'])) {
|
||||
$call['function'] = $trace['function'];
|
||||
}
|
||||
else {
|
||||
$call['function'] = 'main';
|
||||
}
|
||||
|
||||
if (isset($trace['args'])) {
|
||||
foreach ($trace['args'] as $arg) {
|
||||
if (is_scalar($arg)) {
|
||||
$call['args'][] = is_string($arg) ? '\'' . Xss::filter($arg) . '\'' : $arg;
|
||||
}
|
||||
else {
|
||||
$call['args'][] = ucfirst(gettype($arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$return .= $call['function'] . '(' . implode(', ', $call['args']) . ")\n";
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\migrate;
|
||||
|
||||
use Drupal\Core\Utility\Error;
|
||||
use Drupal\migrate\Entity\MigrationInterface;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
|
||||
|
@ -539,7 +540,7 @@ class MigrateExecutable {
|
|||
* in contexts where this doesn't make sense.
|
||||
*/
|
||||
public function handleException($exception, $save = TRUE) {
|
||||
$result = _drupal_decode_exception($exception);
|
||||
$result = Error::decodeException($exception);
|
||||
$message = $result['!message'] . ' (' . $result['%file'] . ':' . $result['%line'] . ')';
|
||||
if ($save) {
|
||||
$this->saveMessage($message);
|
||||
|
|
|
@ -18,6 +18,7 @@ use Drupal\Core\Config\StorageInterface;
|
|||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\StreamWrapper\PublicStream;
|
||||
use Drupal\Core\Utility\Error;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
|
@ -397,7 +398,7 @@ abstract class TestBase {
|
|||
array_shift($backtrace);
|
||||
}
|
||||
|
||||
return _drupal_get_last_caller($backtrace);
|
||||
return Error::getLastCaller($backtrace);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1177,10 +1178,10 @@ abstract class TestBase {
|
|||
if ($severity !== E_USER_NOTICE) {
|
||||
$verbose_backtrace = $backtrace;
|
||||
array_shift($verbose_backtrace);
|
||||
$message .= '<pre class="backtrace">' . format_backtrace($verbose_backtrace) . '</pre>';
|
||||
$message .= '<pre class="backtrace">' . Error::formatBacktrace($verbose_backtrace) . '</pre>';
|
||||
}
|
||||
|
||||
$this->error($message, $error_map[$severity], _drupal_get_last_caller($backtrace));
|
||||
$this->error($message, $error_map[$severity], Error::getLastCaller($backtrace));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1199,14 +1200,15 @@ abstract class TestBase {
|
|||
'line' => $exception->getLine(),
|
||||
'file' => $exception->getFile(),
|
||||
));
|
||||
// The exception message is run through check_plain()
|
||||
// by _drupal_decode_exception().
|
||||
$decoded_exception = _drupal_decode_exception($exception);
|
||||
// The exception message is run through
|
||||
// \Drupal\Component\Utility\checkPlain() by
|
||||
// \Drupal\Core\Utility\decodeException().
|
||||
$decoded_exception = Error::decodeException($exception);
|
||||
unset($decoded_exception['backtrace']);
|
||||
$message = format_string('%type: !message in %function (line %line of %file). <pre class="backtrace">!backtrace</pre>', $decoded_exception + array(
|
||||
'!backtrace' => format_backtrace($verbose_backtrace),
|
||||
'!backtrace' => Error::formatBacktrace($verbose_backtrace),
|
||||
));
|
||||
$this->error($message, 'Uncaught exception', _drupal_get_last_caller($backtrace));
|
||||
$this->error($message, 'Uncaught exception', Error::getLastCaller($backtrace));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,8 +39,8 @@ class ShutdownFunctionsTest extends WebTestBase {
|
|||
$this->assertText(t('First shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2)));
|
||||
$this->assertText(t('Second shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2)));
|
||||
|
||||
// Make sure exceptions displayed through _drupal_render_exception_safe()
|
||||
// are correctly escaped.
|
||||
$this->assertRaw('Drupal is &lt;blink&gt;awesome&lt;/blink&gt;.');
|
||||
// Make sure exceptions displayed through
|
||||
// \Drupal\Core\Utility\Error::renderExceptionSafe() are correctly escaped.
|
||||
$this->assertRaw('Drupal is <blink>awesome</blink>.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ function _system_test_second_shutdown_function($arg1, $arg2) {
|
|||
// Throw an exception with an HTML tag. Since this is called in a shutdown
|
||||
// function, it will not bubble up to the default exception handler but will
|
||||
// be caught in _drupal_shutdown_function() and be displayed through
|
||||
// _drupal_render_exception_safe().
|
||||
// \Drupal\Core\Utility\Error::renderExceptionSafe().
|
||||
throw new Exception('Drupal is <blink>awesome</blink>.');
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Utility\ErrorTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Utility;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\Core\Utility\Error;
|
||||
|
||||
/**
|
||||
* Tests the Error class.
|
||||
*
|
||||
* @group Drupal
|
||||
*
|
||||
* @see \Drupal\Core\Utility\Error
|
||||
*/
|
||||
class ErrorTest extends UnitTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Error',
|
||||
'description' => 'Tests the Error utility class.',
|
||||
'group' => 'Common',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the getLastCaller() method.
|
||||
*
|
||||
* @param array $backtrace
|
||||
* The test backtrace array.
|
||||
* @param array $expected
|
||||
* The expected return array.
|
||||
*
|
||||
* @dataProvider providerTestGetLastCaller
|
||||
*
|
||||
*/
|
||||
public function testGetLastCaller($backtrace, $expected) {
|
||||
$this->assertSame($expected, Error::getLastCaller($backtrace));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testGetLastCaller.
|
||||
*
|
||||
* @return array
|
||||
* An array of parameter data.
|
||||
*/
|
||||
public function providerTestGetLastCaller() {
|
||||
$data = array();
|
||||
|
||||
// Test with just one item. This should default to the function being
|
||||
// main().
|
||||
$single_item = array($this->createBacktraceItem());
|
||||
$data[] = array($single_item, $this->createBacktraceItem('main()'));
|
||||
|
||||
// Add a second item, without a class.
|
||||
$two_items = $single_item;
|
||||
$two_items[] = $this->createBacktraceItem('test_function_two');
|
||||
$data[] = array($two_items, $this->createBacktraceItem('test_function_two()'));
|
||||
|
||||
// Add a second item, with a class.
|
||||
$two_items = $single_item;
|
||||
$two_items[] = $this->createBacktraceItem('test_function_two', 'TestClass');
|
||||
$data[] = array($two_items, $this->createBacktraceItem('TestClass->test_function_two()'));
|
||||
|
||||
// Add blacklist functions to backtrace. They should get removed.
|
||||
foreach (array('debug', '_drupal_error_handler', '_drupal_exception_handler') as $function) {
|
||||
$two_items = $single_item;
|
||||
// Push to the start of the backtrace.
|
||||
array_unshift($two_items, $this->createBacktraceItem($function));
|
||||
$data[] = array($single_item, $this->createBacktraceItem('main()'));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the formatBacktrace() method.
|
||||
*
|
||||
* @param array $backtrace
|
||||
* The test backtrace array.
|
||||
* @param array $expected
|
||||
* The expected return array.
|
||||
*
|
||||
* @dataProvider providerTestFormatBacktrace
|
||||
*/
|
||||
public function testFormatBacktrace($backtrace, $expected) {
|
||||
$this->assertSame($expected, Error::formatBacktrace($backtrace));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testFormatBacktrace.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerTestFormatBacktrace() {
|
||||
$data = array();
|
||||
|
||||
// Test with no function, main should be in the backtrace.
|
||||
$data[] = array(array($this->createBacktraceItem(NULL, NULL)), "main()\n");
|
||||
|
||||
$base = array($this->createBacktraceItem());
|
||||
$data[] = array($base, "test_function()\n");
|
||||
|
||||
// Add a second item.
|
||||
$second_item = $base;
|
||||
$second_item[] = $this->createBacktraceItem('test_function_2');
|
||||
|
||||
$data[] = array($second_item, "test_function()\ntest_function_2()\n");
|
||||
|
||||
// Add a second item, with a class.
|
||||
$second_item_class = $base;
|
||||
$second_item_class[] = $this->createBacktraceItem('test_function_2', 'TestClass');
|
||||
|
||||
$data[] = array($second_item_class, "test_function()\nTestClass->test_function_2()\n");
|
||||
|
||||
// Add a second item, with a class.
|
||||
$second_item_args = $base;
|
||||
$second_item_args[] = $this->createBacktraceItem('test_function_2', NULL, array('string', 10, new \stdClass()));
|
||||
|
||||
$data[] = array($second_item_args, "test_function()\ntest_function_2('string', 10, Object)\n");
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mock backtrace item.
|
||||
*
|
||||
* @param string|NULL $function
|
||||
* (optional) The function name to use in the backtrace item.
|
||||
* @param string $class
|
||||
* (optional) The class to use in the backtrace item.
|
||||
* @param array $args
|
||||
* (optional) An array of function arguments to add to the backtrace item.
|
||||
*
|
||||
* @return array
|
||||
* A backtrace array item.
|
||||
*/
|
||||
protected function createBacktraceItem($function = 'test_function', $class = NULL, array $args = array()) {
|
||||
$backtrace = array(
|
||||
'file' => 'test_file',
|
||||
'line' => 10,
|
||||
'function' => $function,
|
||||
'args' => array(),
|
||||
);
|
||||
|
||||
if (isset($class)) {
|
||||
$backtrace['class'] = $class;
|
||||
$backtrace['type'] = '->';
|
||||
}
|
||||
|
||||
if (!empty($args)) {
|
||||
$backtrace['args'] = $args;
|
||||
}
|
||||
|
||||
return $backtrace;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue