diff --git a/core/includes/errors.inc b/core/includes/errors.inc index f80c8a8..4874f95 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -88,6 +88,8 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line, $c * * @return * An error in the format expected by _drupal_log_error(). + * + * @deprecated Use \Drupal\Core\Utility\Error::decodeException() instead. */ function _drupal_decode_exception($exception) { return Error::decodeException($exception); @@ -101,6 +103,8 @@ function _drupal_decode_exception($exception) { * * @return * An error message. + * + * @deprecated Use \Drupal\Core\Utility\Error::renderExceptionSafe() instead. */ function _drupal_render_exception_safe($exception) { return Error::renderExceptionSafe($exception); @@ -284,6 +288,8 @@ function _drupal_get_error_level() { * * @return * An associative array with keys 'file', 'line' and 'function'. + * + * @deprecated Use \Drupal\Core\Utility\Error::getLastCaller() instead. */ function _drupal_get_last_caller(&$backtrace) { return Error::getLastCaller($backtrace); @@ -299,6 +305,8 @@ function _drupal_get_last_caller(&$backtrace) { * * @return string * A plain-text line-wrapped string ready to be put inside
.
+ *
+ * @deprecated Use \Drupal\Core\Utility\Error::formatBacktrace() instead.
*/
function format_backtrace(array $backtrace) {
return Error::formatBacktrace($backtrace);
diff --git a/core/lib/Drupal/Core/Utility/Error.php b/core/lib/Drupal/Core/Utility/Error.php
index dea27e8..a46a75b 100644
--- a/core/lib/Drupal/Core/Utility/Error.php
+++ b/core/lib/Drupal/Core/Utility/Error.php
@@ -16,6 +16,20 @@
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
@@ -34,9 +48,9 @@ public static function decodeException(\Exception $exception) {
// 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.
+ // 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)) ||
@@ -59,7 +73,7 @@ public static function decodeException(\Exception $exception) {
'%function' => $caller['function'],
'%file' => $caller['file'],
'%line' => $caller['line'],
- 'severity_level' => WATCHDOG_ERROR,
+ 'severity_level' => static::ERROR,
'backtrace' => $backtrace,
);
}
@@ -70,14 +84,14 @@ public static function decodeException(\Exception $exception) {
* @param \Exception $exception
* The exception object that was thrown.
*
- * @return
+ * @return string
* An error message.
*/
public static function renderExceptionSafe(\Exception $exception) {
$decode = static::decodeException($exception);
unset($decode['backtrace']);
- return String::checkPlain(strtr('%type: !message in %function (line %line of %file).', $decode));
+ return String::format('%type: !message in %function (line %line of %file).', $decode);
}
/**
@@ -92,10 +106,8 @@ public static function renderExceptionSafe(\Exception $exception) {
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.
- $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))) {
+ (isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], static::$blacklistFunctions))) {
array_shift($backtrace);
}
@@ -103,7 +115,7 @@ public static function getLastCaller(array &$backtrace) {
// 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.
+ // 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'] . '()';
diff --git a/core/tests/Drupal/Tests/Core/Utility/ErrorTest.php b/core/tests/Drupal/Tests/Core/Utility/ErrorTest.php
index 79aeaca..60910db 100644
--- a/core/tests/Drupal/Tests/Core/Utility/ErrorTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/ErrorTest.php
@@ -7,6 +7,155 @@
namespace Drupal\Tests\Core\Utility;
-class ErrorTest {
+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;
+ }
}