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;
+  }
 
 }