mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
FEATURE Formatting MySQL error messages with newlines through new SQLFormatter class (used in MySQLDatabase)
ENHANCEMENT Using CliDebugView to report errors on ajax requests (with plaintext output) ENHANCEMENT Removed "ERROR:" prefix hack for ajax error responses - clientside evaluation should inspect HTTP status codes instead git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@62467 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
ddc3bab5dc
commit
c57ce5f1a4
@ -423,7 +423,7 @@ abstract class Database extends Object {
|
||||
* @param int $errorLevel The level of the error to throw.
|
||||
*/
|
||||
function databaseError($msg, $errorLevel = E_USER_ERROR) {
|
||||
user_error("DATABASE ERROR: $msg", $errorLevel);
|
||||
user_error($msg, $errorLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -385,6 +385,16 @@ class MySQLDatabase extends Database {
|
||||
public function affectedRows() {
|
||||
return mysql_affected_rows($this->dbConn);
|
||||
}
|
||||
|
||||
function databaseError($msg, $errorLevel = E_USER_ERROR) {
|
||||
// try to extract and format query
|
||||
if(preg_match('/Couldn\'t run query: ([^\|]*)\|\s*(.*)/', $msg, $matches)) {
|
||||
$formatter = new SQLFormatter();
|
||||
$msg = "Couldn't run query: \n" . $formatter->formatPlain($matches[1]) . "\n\n" . $matches[2];
|
||||
}
|
||||
|
||||
user_error($msg, $errorLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -284,7 +284,7 @@ class Debug {
|
||||
* Create an instance of an appropriate DebugView object.
|
||||
*/
|
||||
static function create_debug_view() {
|
||||
if(Director::is_cli()) return new CliDebugView();
|
||||
if(Director::is_cli() || Director::is_ajax()) return new CliDebugView();
|
||||
else return new DebugView();
|
||||
}
|
||||
|
||||
@ -304,33 +304,32 @@ class Debug {
|
||||
$errText = str_replace(array("\n","\r")," ",$errText);
|
||||
header("HTTP/1.0 500 $errText");
|
||||
}
|
||||
if(Director::is_ajax()) {
|
||||
echo "ERROR:Error $errno: $errstr\n At l$errline in $errfile\n";
|
||||
Debug::backtrace();
|
||||
} else {
|
||||
$reporter = self::create_debug_view();
|
||||
|
||||
// Coupling alert: This relies on knowledge of how the director gets its URL, it could be improved.
|
||||
$httpRequest = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_REQUEST['url'];
|
||||
if(isset($_SERVER['REQUEST_METHOD'])) $httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
|
||||
|
||||
// Legacy error handling for customized prototype.js Ajax.Base.responseIsSuccess()
|
||||
// if(Director::is_ajax()) echo "ERROR:\n";
|
||||
|
||||
$reporter = self::create_debug_view();
|
||||
|
||||
// Coupling alert: This relies on knowledge of how the director gets its URL, it could be improved.
|
||||
$httpRequest = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_REQUEST['url'];
|
||||
if(isset($_SERVER['REQUEST_METHOD'])) $httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
|
||||
|
||||
$reporter->writeHeader($httpRequest);
|
||||
$reporter->writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext);
|
||||
$reporter->writeHeader($httpRequest);
|
||||
$reporter->writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext);
|
||||
|
||||
$lines = file($errfile);
|
||||
$lines = file($errfile);
|
||||
|
||||
// Make the array 1-based
|
||||
array_unshift($lines,"");
|
||||
unset($lines[0]);
|
||||
// Make the array 1-based
|
||||
array_unshift($lines,"");
|
||||
unset($lines[0]);
|
||||
|
||||
$offset = $errline-10;
|
||||
$lines = array_slice($lines, $offset, 16, true);
|
||||
$reporter->writeSourceFragment($lines, $errline);
|
||||
$offset = $errline-10;
|
||||
$lines = array_slice($lines, $offset, 16, true);
|
||||
$reporter->writeSourceFragment($lines, $errline);
|
||||
|
||||
$reporter->writeTrace($lines);
|
||||
$reporter->writeFooter();
|
||||
exit(1);
|
||||
}
|
||||
$reporter->writeTrace($lines);
|
||||
$reporter->writeFooter();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
58
parsers/SQLFormatter.php
Normal file
58
parsers/SQLFormatter.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* Format a SQL Query for better readable output in HTML or Plaintext.
|
||||
* Its a simple string parser, not a full tokenizer - so formatting
|
||||
* is not aware of the SQL syntax. This means we have to be conservative
|
||||
* with modifying the SQL string.
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage parsers
|
||||
* @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com)
|
||||
* @usedby Database->databaseError()
|
||||
*/
|
||||
class SQLFormatter extends Object {
|
||||
|
||||
protected static $newline_before_tokens = array(
|
||||
'SELECT',
|
||||
'UPDATE',
|
||||
'INSERT',
|
||||
'DELETE',
|
||||
'FROM',
|
||||
'INNER JOIN',
|
||||
'FULL JOIN',
|
||||
'LEFT JOIN',
|
||||
'RIGHT JOIN',
|
||||
'WHERE',
|
||||
'ORDER BY',
|
||||
'GROUP BY',
|
||||
'LIMIT',
|
||||
);
|
||||
|
||||
public function formatPlain($sql) {
|
||||
$sql = $this->addNewlines($sql, false);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function formatHTML($sql) {
|
||||
$sql = $this->addNewlines($sql, true);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Newlines for tokens defined in $newline_before_tokens.
|
||||
* Case-sensitive, only applies to uppercase SQL to avoid
|
||||
* messing with possible content fragments in the query.
|
||||
*/
|
||||
protected function addNewlines($sql, $useHtmlFormatting = false) {
|
||||
foreach(self::$newline_before_tokens as $token) {
|
||||
$breakToken = ($useHtmlFormatting) ? "<br />\n" : "\n";
|
||||
$sql = preg_replace('/[^\n](' . $token . ')/', $breakToken . '$1', $sql);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
41
tests/SQLFormatterTest.php
Normal file
41
tests/SQLFormatterTest.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class SQLFormatterTest extends SapphireTest {
|
||||
|
||||
function testNewlineHanding() {
|
||||
$formatter = new SQLFormatter();
|
||||
|
||||
$sqlBefore = <<<SQL
|
||||
SELECT Test.Foo, Test.Bar FROM Test WHERE 'From' = "Where"
|
||||
SQL;
|
||||
$sqlAfter = <<<SQL
|
||||
SELECT Test.Foo, Test.Bar
|
||||
FROM Test
|
||||
WHERE 'From' = "Where"
|
||||
SQL;
|
||||
$this->assertEquals($formatter->formatPlain($sqlBefore), $sqlAfter,
|
||||
'correct replacement of newlines and don\'t replace non-uppercase tokens'
|
||||
);
|
||||
|
||||
$sqlBefore = <<<SQL
|
||||
SELECT Test.Foo, Test.Bar
|
||||
FROM Test
|
||||
WHERE
|
||||
'From' = "Where"
|
||||
SQL;
|
||||
$sqlAfter = <<<SQL
|
||||
SELECT Test.Foo, Test.Bar
|
||||
FROM Test
|
||||
WHERE
|
||||
'From' = "Where"
|
||||
SQL;
|
||||
$this->assertEquals($formatter->formatPlain($sqlBefore), $sqlAfter,
|
||||
'Leave existing newlines and indentation in place'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
Loading…
x
Reference in New Issue
Block a user