Browse Source

Errors and exceptions handling, #16

git-svn-id: svn+ssh://code.netmonsters.ru/svn/majestic/branches/evo@121 4cb57b5f-5bbd-dd11-951b-001d605cbbc5
master
pzinovkin 15 years ago
parent
commit
4f7e5b00bc
  1. 59
      app/ErrorAction.php
  2. 36
      app/FrontController.php
  3. 34
      classes/Env.class.php
  4. 13
      exception/Error404Exception.php
  5. 190
      exception/ErrorHandler.php
  6. 19
      exception/GeneralException.php
  7. 10
      view/PHPView.php

59
app/ErrorAction.php

@ -0,0 +1,59 @@
<?php
/**
* @copyright NetMonsters <team@netmonsters.ru>
* @link http://netmonsters.ru
* @package Majestic
* @subpackage app
* @since 2010-02-25
* @version SVN: $Id$
* @filesource $URL$
*/
class ErrorAction extends ViewAction
{
/**
* @var Exception
*/
protected $exception;
public function __construct($exception)
{
$this->exception = $exception;
$this->view = FrontController::getInstance()->getView();
$this->execute();
}
protected function execute()
{
$this->template = 500;
if ($this->exception instanceof Error404Exception) {
$this->template = 404;
}
}
protected function getTemplate()
{
return '/static/' . $this->template;
}
protected function sendHttpCode($code)
{
if (headers_sent()) {
return;
}
switch ($code) {
case 404:
header('HTTP/1.0 404 Not Found');
break;
default:
header('HTTP/1.0 500 Internal Server Error');
}
}
public function fetch()
{
$this->sendHTTPCode($this->template);
return $this->view->fetch($this->getTemplate());
}
}

36
app/FrontController.php

@ -21,11 +21,6 @@ class FrontController
*/ */
protected $view = 'PHPView'; protected $view = 'PHPView';
/**
* @var string
*/
protected $view_path;
protected $base_url = ''; protected $base_url = '';
/** /**
@ -36,9 +31,13 @@ class FrontController
private function __construct() private function __construct()
{ {
ErrorHandler::init();
$this->router = new Router(); $this->router = new Router();
} }
/**
* Refuse cloning
*/
private function __clone(){} private function __clone(){}
/** /**
@ -53,16 +52,6 @@ class FrontController
} }
/** /**
* @param string $path
* @return FrontController
*/
public function setViewPath($path)
{
$this->view_path = $path;
return $this;
}
/**
* @param string $view * @param string $view
* @return FrontController * @return FrontController
*/ */
@ -79,7 +68,7 @@ class FrontController
public function getView($view = null) public function getView($view = null)
{ {
$view = ($view) ? $view : $this->view; $view = ($view) ? $view : $this->view;
return new $view($this->view_path);
return new $view(Config::get($view));
} }
/** /**
@ -106,13 +95,12 @@ class FrontController
public function execute() public function execute()
{ {
try {
try { try {
$request = Env::getRequestUri(); $request = Env::getRequestUri();
$route = $this->getRouter()->route($request); $route = $this->getRouter()->route($request);
if (!$route) { if (!$route) {
throw new Exception('Route "' . $request . '" not found');
throw new Error404Exception('Route "' . $request . '" not found');
} }
$action_class = $route->getAction(); $action_class = $route->getAction();
@ -120,15 +108,13 @@ class FrontController
$layout_class = $route->getLayout(); $layout_class = $route->getLayout();
$layout = new $layout_class(); $layout = new $layout_class();
return $layout->fetch($action); return $layout->fetch($action);
} catch (GeneralException $e) {
throw $e;
} catch (Exception $e) {
throw new GeneralException($e->getMessage(), $e->getCode());
}
} catch(Exception $e) { } catch(Exception $e) {
if (DEBUG == true) { if (DEBUG == true) {
return $e->toHtml();
return ErrorHandler::showDebug($e);
} }
$layout = new DefaultLayout();
return $layout->fetch(new ErrorAction($e));
} }
} }
} }

34
classes/Env.class.php

@ -30,19 +30,36 @@ class Env
return self::$request; return self::$request;
} }
static public function Get($var, $default = false)
static public function Get($key = null, $default = null)
{ {
return isset($_GET[$var]) ? $_GET[$var] : $default;
if ($key === null) {
return $_GET;
}
return (isset($_GET[$key])) ? $_GET[$key] : $default;
}
static public function Post($key = null, $default = null)
{
if ($key === null) {
return $_POST;
}
return (isset($_POST[$key])) ? $_POST[$key] : $default;
} }
static public function Post($var, $default = false)
static public function Cookie($key = null, $default = false)
{ {
return isset($_POST[$var]) ? $_POST[$var] : $default;
if ($key === null) {
return $_COOKIE;
}
return (isset($_COOKIE[$key])) ? $_COOKIE[$key] : $default;
} }
static public function Server($var, $default = false)
static public function Server($key = null, $default = null)
{ {
return isset($_SERVER[$var]) ? $_SERVER[$var] : $default;
if ($key === null) {
return $_SERVER;
}
return (isset($_SERVER[$key])) ? $_SERVER[$key] : $default;
} }
static public function Session($var, $default = false) static public function Session($var, $default = false)
@ -67,11 +84,6 @@ class Env
} }
} }
static public function getCookie($var, $default = false)
{
return isset($_COOKIE[$var]) ? $_COOKIE[$var] : $default;
}
static public function setCookie($var, $value, $time = 0, $path = '/') static public function setCookie($var, $value, $time = 0, $path = '/')
{ {
return setcookie($var, $value, $time, $path); return setcookie($var, $value, $time, $path);

13
exception/Error404Exception.php

@ -9,15 +9,4 @@
* @filesource $URL$ * @filesource $URL$
*/ */
class Error404Exception extends GeneralException
{
protected $code = 404;
protected function sendHeader()
{
if (! headers_sent()) {
header('HTTP/1.0 404 Not Found');
}
}
}
class Error404Exception extends GeneralException {}

190
exception/ErrorHandler.php

@ -0,0 +1,190 @@
<?php
/**
* @copyright NetMonsters <team@netmonsters.ru>
* @link http://netmonsters.ru
* @package Majestic
* @subpackage exception
* @since 2010-02-26
* @version SVN: $Id$
* @filesource $URL$
*/
class ErrorHandler
{
static public function init()
{
set_error_handler(array('ErrorHandler', 'error_handler'));
}
static public function error_handler($errno, $errstr, $errfile, $errline )
{
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
return false;
}
static protected function getSource($file, $hiline)
{
$code = array();
$i = 0;
foreach(file($file) as $line) {
$i++;
if($i >= $hiline - 10 && $i <= $hiline + 10) {
if ($i == $hiline) {
$code[] = '<tr class="error"><th>' . $i . '</th><td><span class="specific">' . $line . '</span></td></tr>';
}else{
$code[] = '<tr><th>' . $i . '</th><td>' . $line . '</td></tr>';
}
}
if($i > $hiline + 10) {
break;
}
}
return implode('', $code);
}
static protected function wrapArray($array, $name)
{
if (!$array) {
return '<p>No ' . $name . ' data</p>';
}
$text = '<table class="req"><thead><tr><th>Variable</th><th>Value</th></tr></thead><tbody>';
foreach ($array as $key => $value) {
$text .= '<tr><td>' . $key . '</td><td class="code"><div>' . $value . '</div></td></tr>';
}
$text .= '</tbody></table>';
return $text;
}
static protected function wrapTrace($trace)
{
return '<code>' . nl2br($trace) . '</code>';
}
/**
* @param Exception $exception
*/
static public function showDebug($exception)
{
$class = get_class($exception);
$method = Env::Server('REQUEST_METHOD', '');
$uri = Env::getRequestUri();
$source = self::getSource($exception->getFile(), $exception->getLine());
$time = date('r', Env::Server('REQUEST_TIME', time()));
$trace = self::wrapTrace($exception->getTraceAsString());
$get = self::wrapArray(Env::Get(), 'GET');
$post = self::wrapArray(Env::Post(), 'POST');
$files = self::wrapArray(Env::Files(), 'FILES');
$cookies = self::wrapArray(Env::Cookie(), 'COOKIE');
$server = self::wrapArray(Env::Server(), 'SERVER');
$message =<<<EOD
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>{$class} at {$uri}</title>
<style type="text/css">
html * { padding:0; margin:0; }
body * { padding:10px 20px; }
body * * { padding:0; }
body { font:small sans-serif; }
body>div { border-bottom:1px solid #ddd; }
h1 { font-weight:normal; }
h2 { margin-bottom:.8em; }
h2 span { font-size:80%; color:#666; font-weight:normal; }
h3 { margin:1em 0 .5em 0; }
h4 { margin:0 0 .5em 0; font-weight: normal; }
table { border:1px solid #ccc; border-collapse: collapse; width:100%; background:white; }
tbody td, tbody th { vertical-align:top; padding:2px 3px; }
thead th { padding:1px 6px 1px 3px; background:#fefefe; text-align:left; font-weight:normal; font-size:11px; border:1px solid #ddd; }
tbody th { width:12em; text-align:right; color:#666; padding-right:.5em; }
table.vars { margin:5px 0 2px 40px; }
table.vars td, table.req td { font-family:monospace; }
table td.code { width:100%; }
table td.code div { overflow:hidden; }
table.source th { color:#666; }
table.source td { font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
ul.traceback { list-style-type:none; }
ul.traceback li.frame { margin-bottom:1em; }
div.context { margin: 10px 0; }
div.context ol { padding-left:30px; margin:0 10px; list-style-position: inside; }
div.context ol li { font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
div.context ol.context-line li { color:black; background-color:#ccc; }
div.context ol.context-line li span { float: right; }
div.commands { margin-left: 40px; }
div.commands a { color:black; text-decoration:none; }
#summary { background: #ffc; }
#summary h2 { font-weight: normal; color: #666; }
#explanation { background:#eee; }
#source{ background:#f6f6f6; }
#traceback { background:#eee; }
#requestinfo { background:#f6f6f6; padding-left:120px; }
#summary table { border:none; background:transparent; }
#requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
#requestinfo h3 { margin-bottom:-1em; }
.error { background: #ffc; }
.specific { color:#cc3300; font-weight:bold; }
h2 span.commands { font-size:.7em;}
span.commands a:link {color:#5E5694;}
pre.exception_value { font-family: sans-serif; color: #666; font-size: 1.5em; margin: 10px 0 10px 0; }
</style>
</head>
<body>
<div id="summary">
<h1>{$class} at {$uri}</h1>
<pre class="exception_value">{$exception->getMessage()}</pre>
<table class="meta">
<tbody>
<tbody>
<tr><th>Request Method:</th><td>{$method}</td></tr>
<tr><th>Exception Type:</th><td>{$class}</td></tr>
<tr><th>Exception Message:</th><td><pre>{$exception->getMessage()}</pre></td></tr>
<tr><th>Exception Location:</th><td>{$exception->getFile()}, line {$exception->getLine()}</td></tr>
<tr><th>Server time:</th><td>{$time}</td></tr>
</tbody>
</table>
</div>
<div id="source">
<h2>Context</h2>
<p>In file <code>{$exception->getFile()}</code>, error at line <strong>{$exception->getLine()}</strong></p>
<h3>{$exception->getMessage()}</h3>
<table class="source cut-top">
<tbody>{$source}</tbody>
</table>
</div>
<div id="traceback">
<h2>Traceback</h2>
<div id="browserTraceback">{$trace}</div>
</div>
<div id="requestinfo">
<h2>Request information</h2>
<h3 id="get-info">GET</h3>
{$get}
<h3 id="post-info">POST</h3>
{$post}
<h3 id="files-info">FILES</h3>
{$files}
<h3 id="cookie-info">COOKIES</h3>
{$cookies}
<h3 id="meta-info">SERVER</h3>
{$server}
<h3 id="settings-info">Settings</h3>
<p>todo</p>
</div>
<div id="explanation">
<p>You're seeing this error because you have defined constant <code>DEBUG = True</code> in your config file. Change that to <code>False</code>, and it will display a standard 500 page.</p>
</div>
</body>
</html>
EOD;
return $message;
}
}

19
exception/GeneralException.php

@ -9,21 +9,4 @@
* @filesource $URL$ * @filesource $URL$
*/ */
class GeneralException extends Exception
{
protected $code = 500;
protected function sendHeader()
{
if (!headers_sent()) {
header('HTTP/1.0 500 Internal Server Error');
}
}
public function toHtml()
{
$this->sendHeader();
return 'Exception caught: ' . $this->getMessage();
}
}
class GeneralException extends Exception {}

10
view/PHPView.php

@ -17,9 +17,12 @@ class PHPView implements iView
protected $extension = '.phtml'; protected $extension = '.phtml';
protected $template = ''; protected $template = '';
public function __construct($path)
public function __construct($config)
{ {
$this->setPath($path);
if (!isset($config['path'])) {
throw new Exception('Configuration must have a "host".');
}
$this->setPath($config['path']);
} }
public function getPath() public function getPath()
@ -53,10 +56,11 @@ class PHPView implements iView
unset($template); unset($template);
extract($this->variables); extract($this->variables);
ob_start(); ob_start();
if (!(include($this->template)) == 'OK') {
if (!is_readable($this->template)) {
ob_clean(); ob_clean();
throw new Exception('Template "' . $this->template .'" not found.'); throw new Exception('Template "' . $this->template .'" not found.');
} }
include($this->template);
return ob_get_clean(); return ob_get_clean();
} }

Loading…
Cancel
Save