diff options
Diffstat (limited to 'framework/Exceptions')
-rw-r--r-- | framework/Exceptions/TErrorHandler.php | 99 | ||||
-rw-r--r-- | framework/Exceptions/TException.php | 65 | ||||
-rw-r--r-- | framework/Exceptions/messages.txt | 3 | ||||
-rw-r--r-- | framework/Exceptions/templates/exception-en.html | 3 | ||||
-rw-r--r-- | framework/Exceptions/templates/exception-fr.html | 3 | ||||
-rw-r--r-- | framework/Exceptions/templates/exception-zh.html | 3 |
6 files changed, 148 insertions, 28 deletions
diff --git a/framework/Exceptions/TErrorHandler.php b/framework/Exceptions/TErrorHandler.php index 14c824c9..869ccb00 100644 --- a/framework/Exceptions/TErrorHandler.php +++ b/framework/Exceptions/TErrorHandler.php @@ -207,39 +207,34 @@ class TErrorHandler extends TModule */
protected function displayException($exception)
{
- $fileName=$exception->getFile();
- $errorLine=$exception->getLine();
- if($exception instanceof TPhpErrorException)
+
+ if($exception instanceof TTemplateException)
{
- // if PHP exception, we want to show the 2nd stack level context
- // because the 1st stack level is of little use (it's in error handler)
- $trace=$exception->getTrace();
- if(isset($trace[1]) && isset($trace[1]['file']) && isset($trace[1]['line']))
- {
- $fileName=$trace[1]['file'];
- $errorLine=$trace[1]['line'];
- }
+ $fileName=$exception->getTemplateFile();
+ $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName);
+ $source=$this->getSourceCode($lines,$exception->getLineNumber());
+ if($fileName==='')
+ $fileName='---embedded template---';
+ $errorLine=$exception->getLineNumber();
}
- $lines=file($fileName);
-
- $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
- $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
-
- $source='';
- for($i=$beginLine;$i<$endLine;++$i)
+ else
{
- if($i===$errorLine-1)
+ if(($trace=$this->getExactTrace($exception))!==null)
{
- $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
- $source.="<div class=\"error\">".$line."</div>";
+ $fileName=$trace['file'];
+ $errorLine=$trace['line'];
}
else
- $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ {
+ $fileName=$exception->getFile();
+ $errorLine=$exception->getLine();
+ }
+ $source=$this->getSourceCode(@file($fileName),$errorLine);
}
$tokens=array(
'%%ErrorType%%' => get_class($exception),
- '%%ErrorMessage%%' => htmlspecialchars($exception->getMessage()),
+ '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())),
'%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')',
'%%SourceCode%%' => $source,
'%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()),
@@ -254,6 +249,64 @@ class TErrorHandler extends TModule die("Unable to open exception template file '$exceptionFile'.");
echo strtr($content,$tokens);
}
+
+ private function getExactTrace($exception)
+ {
+ $trace=$exception->getTrace();
+ $result=null;
+ // if PHP exception, we want to show the 2nd stack level context
+ // because the 1st stack level is of little use (it's in error handler)
+ if($exception instanceof TPhpErrorException)
+ $result=$trace[1];
+ else if($exception instanceof TInvalidOperationException)
+ {
+ // in case of getter or setter error, find out the exact file and row
+ if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null)
+ $result=$this->getPropertyAccessTrace($trace,'__set');
+ }
+ if($result!==null && strpos($result['file'],': eval()\'d code')!==false)
+ return null;
+
+ return $result;
+ }
+
+ private function getPropertyAccessTrace($trace,$pattern)
+ {
+ $result=null;
+ foreach($trace as $t)
+ {
+ if(isset($t['function']) && $t['function']===$pattern)
+ $result=$t;
+ else
+ break;
+ }
+ return $result;
+ }
+
+ private function getSourceCode($lines,$errorLine)
+ {
+ $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
+ $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
+
+ $source='';
+ for($i=$beginLine;$i<$endLine;++$i)
+ {
+ if($i===$errorLine-1)
+ {
+ $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ $source.="<div class=\"error\">".$line."</div>";
+ }
+ else
+ $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ }
+ return $source;
+ }
+
+ private function addLink($message)
+ {
+ $baseUrl='http://www.pradosoft.com/docs/classdoc';
+ return preg_replace('/(T[A-Z]\w+)/',"<a href=\"$baseUrl/\${1}\" target=\"_blank\">\${1}</a>",$message);
+ }
}
?>
\ No newline at end of file diff --git a/framework/Exceptions/TException.php b/framework/Exceptions/TException.php index 745d5769..6f9a8a3f 100644 --- a/framework/Exceptions/TException.php +++ b/framework/Exceptions/TException.php @@ -209,6 +209,71 @@ class TConfigurationException extends TSystemException }
/**
+ * TTemplateException class
+ *
+ * TTemplateException represents an exception caused by invalid template syntax.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Exceptions
+ * @since 3.1
+ */
+class TTemplateException extends TConfigurationException
+{
+ private $_template='';
+ private $_lineNumber=0;
+ private $_fileName='';
+
+ /**
+ * @return string the template source code that causes the exception. This is empty if {@link getTemplateFile TemplateFile} is not empty.
+ */
+ public function getTemplateSource()
+ {
+ return $this->_template;
+ }
+
+ /**
+ * @param string the template source code that causes the exception
+ */
+ public function setTemplateSource($value)
+ {
+ $this->_template=$value;
+ }
+
+ /**
+ * @return string the template file that causes the exception. This could be empty if the template is an embedded template. In this case, use {@link getTemplateSource TemplateSource} to obtain the actual template content.
+ */
+ public function getTemplateFile()
+ {
+ return $this->_fileName;
+ }
+
+ /**
+ * @param string the template file that causes the exception
+ */
+ public function setTemplateFile($value)
+ {
+ $this->_fileName=$value;
+ }
+
+ /**
+ * @return integer the line number at which the template has error
+ */
+ public function getLineNumber()
+ {
+ return $this->_lineNumber;
+ }
+
+ /**
+ * @param integer the line number at which the template has error
+ */
+ public function setLineNumber($value)
+ {
+ $this->_lineNumber=TPropertyValue::ensureInteger($value);
+ }
+}
+
+/**
* TIOException class
*
* TIOException represents an exception related with improper IO operations.
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index b35ba7bf..79fdb8d1 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -124,8 +124,7 @@ template_property_readonly = {0} has a read-only property '{1}'. template_event_forbidden = {0} is a non-control component. No handler can be attached to its event '{1}' in a template.
template_databind_forbidden = {0} is a non-control component. Expressions cannot be bound to its property '{1}'.
template_component_required = '{0}' is not a component. Only components can appear in a template.
-template_format_invalid = Error in {0} (line {1}) : {2}
-template_format_invalid2 = Error at line {0} of the following template: {1} {2}
+template_format_invalid = Invalid template syntax: {0}
template_property_duplicated = Property {0} is configured twice or more.
template_eventhandler_invalid = {0}.{1} can only accept a static string.
template_controlid_invalid = {0}.ID can only accept a static text string.
diff --git a/framework/Exceptions/templates/exception-en.html b/framework/Exceptions/templates/exception-en.html index f9012206..aed3755d 100644 --- a/framework/Exceptions/templates/exception-en.html +++ b/framework/Exceptions/templates/exception-en.html @@ -1,4 +1,4 @@ -<!DOCTYPE html PUBLIC
+<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
@@ -12,6 +12,7 @@ h1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red } h2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
h3 {font-family:"Verdana";font-weight:bold;font-size:11pt}
p {font-family:"Verdana";font-weight:normal;color:black;font-size:9pt;margin-top: -5px}
+a {font-family:"Verdana";color:red;}
code,pre {font-family:"Lucida Console";font-size:10pt;}
td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
.source {font-family:"Lucida Console";font-weight:normal;background-color:#ffffee;}
diff --git a/framework/Exceptions/templates/exception-fr.html b/framework/Exceptions/templates/exception-fr.html index 993ef39e..7cb61361 100644 --- a/framework/Exceptions/templates/exception-fr.html +++ b/framework/Exceptions/templates/exception-fr.html @@ -1,4 +1,4 @@ -<!DOCTYPE html PUBLIC
+<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
@@ -11,6 +11,7 @@ h1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red } h2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
h3 {font-family:"Verdana";font-weight:bold;font-size:11pt}
p {font-family:"Verdana";font-weight:normal;color:black;font-size:9pt;margin-top: -5px}
+a {font-family:"Verdana";color:red;}
code,pre {font-family:"Lucida Console";font-size:10pt;}
td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
.source {font-family:"Lucida Console";font-weight:normal;background-color:#ffffee;}
diff --git a/framework/Exceptions/templates/exception-zh.html b/framework/Exceptions/templates/exception-zh.html index ddfe9473..257e8e69 100644 --- a/framework/Exceptions/templates/exception-zh.html +++ b/framework/Exceptions/templates/exception-zh.html @@ -1,4 +1,4 @@ -<!DOCTYPE html PUBLIC
+<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh" lang="zh">
@@ -12,6 +12,7 @@ h1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red } h2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
h3 {font-family:"Verdana";font-weight:bold;font-size:11pt}
p {font-family:"Verdana";font-weight:normal;color:black;font-size:9pt;margin-top: -5px}
+a {font-family:"Verdana";color:red;}
code,pre {font-family:"Lucida Console";font-size:10pt;}
td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
.source {font-family:"Lucida Console";font-weight:normal;background-color:#ffffee;}
|