From 3482b5c4d91eb1c026752f96fd03175057ce9a27 Mon Sep 17 00:00:00 2001 From: John Le Drew Date: Fri, 2 Jul 2010 15:19:08 +0100 Subject: [PATCH] error handler improvements --- source/lib/simplicity/core/cache/cache.php | 7 +- source/lib/simplicity/core/error/error.php | 146 ++------ source/lib/simplicity/core/error/error_handler.php | 45 +++ .../simplicity/core/error/handlers/basic/basic.php | 12 + .../fatal.phtml => handlers/basic/default.phtml} | 18 +- .../default.phtml => handlers/basic/fatal.phtml} | 11 - .../fatal.phtml => handlers/http/default.phtml} | 18 +- .../simplicity/core/error/handlers/http/http.php | 21 ++ .../simplicity/core/error/handlers/json/basic.php | 12 + .../simplicity/core/error/templates/default.phtml | 10 +- .../simplicity/core/error/templates/fatal.phtml | 11 - source/lib/simplicity/core/template/plugin.php | 32 ++ source/lib/simplicity/core/template/template.php | 366 +++++++++++++++++++++ source/lib/simplicity/simplicity.php | 15 +- source/public/index.php | 2 +- 15 files changed, 535 insertions(+), 191 deletions(-) create mode 100644 source/lib/simplicity/core/error/error_handler.php create mode 100644 source/lib/simplicity/core/error/handlers/basic/basic.php copy source/lib/simplicity/core/error/{templates/fatal.phtml => handlers/basic/default.phtml} (51%) copy source/lib/simplicity/core/error/{templates/default.phtml => handlers/basic/fatal.phtml} (61%) copy source/lib/simplicity/core/error/{templates/fatal.phtml => handlers/http/default.phtml} (51%) create mode 100644 source/lib/simplicity/core/error/handlers/http/http.php create mode 100644 source/lib/simplicity/core/error/handlers/json/basic.php create mode 100755 source/lib/simplicity/core/template/plugin.php create mode 100755 source/lib/simplicity/core/template/template.php diff --git a/source/lib/simplicity/core/cache/cache.php b/source/lib/simplicity/core/cache/cache.php index 6062f63..72ad751 100755 --- a/source/lib/simplicity/core/cache/cache.php +++ b/source/lib/simplicity/core/cache/cache.php @@ -55,12 +55,7 @@ class smp_CacheModule extends smp_Module * */ private function loadBackend() - { - /* - $backend = $backend ? $backend : 'auto'; - $options = is_array($options) ? $options : array(); - */ - + { $backend = $this->getConfig('backend.module'); $options = $this->getConfig('backend.options'); diff --git a/source/lib/simplicity/core/error/error.php b/source/lib/simplicity/core/error/error.php index 5f54b2c..b71f0df 100755 --- a/source/lib/simplicity/core/error/error.php +++ b/source/lib/simplicity/core/error/error.php @@ -13,30 +13,18 @@ */ class smp_ErrorModule extends smp_Module { - private $_handled = false; - - private $_types = array( - 'text/html' => 'html', - 'application/json' => 'json', - 'text/xml' => 'xml' - ); - - public function addType($mime,$name) - { - $this->_types[$mime] = $name; - } + private $_handled = false; + /** * @inherited */ protected function init() { - $this->setDefault('view_path',dirname(__FILE__).DS.'templates'.DS); - $this->setDefault('layout',false); - $this->setDefault('logging',false); - $this->setDefault('mode','live'); + $this->setDefault('enabled',true); + $this->setDefault('chain',array('Basic')); - $this->createExtensionPoint('smp_Exception'); + $this->createExtensionPoint('smp_ErrorHandler'); $this->registerPluginPrefix('smp_'); } @@ -45,11 +33,14 @@ class smp_ErrorModule extends smp_Module */ public function exec($args=array()) { - ini_set('display_errors',0); error_reporting(-1); - register_shutdown_function(array($this,'shutdown')); - set_error_handler(array($this,'error')); - set_exception_handler(array($this,'exception')); + + if ($this->getConfig('enabled')) { + ini_set('display_errors',0); + register_shutdown_function(array($this,'shutdown')); + set_error_handler(array($this,'error')); + set_exception_handler(array($this,'exception')); + } } /** @@ -59,7 +50,7 @@ class smp_ErrorModule extends smp_Module { restore_error_handler(); $this->_handled = true; - throw new smp_Exception($errstr,$errline,$errno,$errfile); + $this->handle(new smp_Exception($errstr,$errline,$errno,$errfile)); } /** @@ -76,7 +67,7 @@ class smp_ErrorModule extends smp_Module if (!is_null($e)) { $e = new smp_FatalException('Fatal error: '.$e['message'],$e['line'],$e['type'],$e['file'],$GLOBALS,array()); - $this->render($e); + $this->handle($e); } } @@ -94,7 +85,7 @@ class smp_ErrorModule extends smp_Module $e = new smp_Exception($e->getMessage(),$e->getLine(),$e->getCode(),$e->getFile()); } - $this->render($e); + $this->handle($e); } public function getErrorReport($ref) @@ -204,108 +195,17 @@ class smp_ErrorModule extends smp_Module return $ref; } - private function render(smp_Exception $e) + private function handle(smp_Exception $e) { - $msg = $e->getMessage() . ' on line ' . $e->getLine() . ' in file ' . $e->getFile(); + $chain = $this->getConfig('chain'); - restore_error_handler(); - restore_exception_handler(); - - $log_ref = false; - if ($this->getConfig('logging')) $log_ref = $this->logException($e); - - if (ob_get_level()) ob_end_clean(); - - ob_implicit_flush(true); - - $accept = smp_Request::getInstance()->getHeader('accept'); - - if (is_array($accept)) { - $type = isset($accept[0]) ? $accept[0] : 'text/html'; - } - else { - $type = $accept ? $accept : 'text/html'; - } - - $type = isset($this->_types[$type]) ? $this->_types[$type] : 'html'; - - $class = get_class($e); - if ($class == 'smp_Exception') { - $module = "default"; - } - else { - $module = smp_String::underscore($this->getClassModule($class)); - } - - $code = $e->getCode(); - - $root = $this->getConfig('view_path'); - - if (!$template = $this->getTemplate($root,$module,$type,$code)) { - $rt = dirname(__FILE__).DS.'templates'.DS; - if ($root == $rt) { - $template = false; - } - else { - $template = $this->getTemplate($root,$module,$type,$code); - } - } - - if ($e instanceof smp_HttpException) { - smp_Response::getInstance()->setStatus($e->getCode()); - } - else { - smp_Response::getInstance()->setStatus(500); - } - - if ($template) { - $t = new smp_Template($template); - $t->set('exception',$e); - $t->set('logging_ref',$log_ref); - $t->set('mode',$this->getConfig('mode')); - $content = $t->renderTemplate(); - } - else { - $e = print_r($e,true); - $content = "

Error template not found. Logging ref: {$log_ref}

{$e}
"; - } - - if ($type == 'html' && $layout = $this->getConfig('layout')) { - if (file_exists($layout)) { - $l = new smp_Template($layout); - $l->set('content',$content); - $l->set('logging_ref',$log_ref); - $l->set('exception',$e); - $l->set('mode',$this->getConfig('mode')); - $content = $l->renderTemplate(); - } - } - - smp_Response::getInstance()->setContent($content); - - smp_Response::getInstance()->sendStatus(); - smp_Response::getInstance()->sendHeaders(); - smp_Response::getInstance()->sendContent(); - - die(); - } - - private function getTemplate($root,$module,$type,$code) - { - $template = "{$root}{$module}.{$type}.{$code}.phtml"; - if (!file_exists($template)) { - $template = "{$root}{$module}.{$type}.phtml"; - if (!file_exists($template)) { - $template = "{$root}{$module}.phtml"; - if (!file_exists($template)) { - $template = "{$root}default.phtml"; - if (!file_exists($template)) { - return false; - } - } - } + while ($module = array_shift($chain)) { + $cls = $this->getModuleClass($module); + $mod = new $cls($this,$e,$module); + $mod->handle(); + $e = $mod->getException(); } - return $template; + $this->getSimplicity()->clearCurrentChain(); } } \ No newline at end of file diff --git a/source/lib/simplicity/core/error/error_handler.php b/source/lib/simplicity/core/error/error_handler.php new file mode 100644 index 0000000..c9dce61 --- /dev/null +++ b/source/lib/simplicity/core/error/error_handler.php @@ -0,0 +1,45 @@ +_error = $error; + $this->_exception = $e; + $alias = smp_String::underscore($alias); + $this->_config = "modules.error.{$alias}"; + + $this->init(); + } + + final protected function getConfig($path=null) + { + if (!isset($path)) $path = ""; + $path = "{$this->_config}.$path"; + return $this->getError()->getSimplicity()->getConfig($path); + } + + /** + * @return smp_ErrorModule + */ + final protected function getError() + { + return $this->_error; + } + + /** + * @return smp_Exception + */ + final public function getException() + { + return $this->_exception; + } + + public function init() {} + + abstract public function handle(); +} \ No newline at end of file diff --git a/source/lib/simplicity/core/error/handlers/basic/basic.php b/source/lib/simplicity/core/error/handlers/basic/basic.php new file mode 100644 index 0000000..9b50c0a --- /dev/null +++ b/source/lib/simplicity/core/error/handlers/basic/basic.php @@ -0,0 +1,12 @@ +exception = $this->getException(); + + smp_Response::getInstance()->setContent($t->renderTemplate()); + smp_Response::getInstance()->setStatus(500); + } +} \ No newline at end of file diff --git a/source/lib/simplicity/core/error/templates/fatal.phtml b/source/lib/simplicity/core/error/handlers/basic/default.phtml similarity index 51% copy from source/lib/simplicity/core/error/templates/fatal.phtml copy to source/lib/simplicity/core/error/handlers/basic/default.phtml index 139d28b..edda00a 100755 --- a/source/lib/simplicity/core/error/templates/fatal.phtml +++ b/source/lib/simplicity/core/error/handlers/basic/default.phtml @@ -1,21 +1,15 @@ - -mode != 'live') { ?> -

exception->getMessage(); ?>

File

exception->getFile(); ?> on line exception->getLine(); ?>

+exception instanceof smp_FatalException)) { ?> +

Trace

+
exception->getSafeTrace()); ?>
+ +

Context

exception->getContext()); ?>

Headers

-
exception->getHeaders()); ?>
- - - -

I18n()->t('error.title'); ?>

-
Textile()->convert($this->I18n()->t('error.desc')); ?>
- - - +
exception->getHeaders()); ?>
\ No newline at end of file diff --git a/source/lib/simplicity/core/error/templates/default.phtml b/source/lib/simplicity/core/error/handlers/basic/fatal.phtml similarity index 61% copy from source/lib/simplicity/core/error/templates/default.phtml copy to source/lib/simplicity/core/error/handlers/basic/fatal.phtml index 17f0d35..1a867f4 100755 --- a/source/lib/simplicity/core/error/templates/default.phtml +++ b/source/lib/simplicity/core/error/handlers/basic/fatal.phtml @@ -1,21 +1,10 @@ -mode != 'live') { ?> -

exception->getMessage(); ?>

File

exception->getFile(); ?> on line exception->getLine(); ?>

-

Trace

-
exception->getSafeTrace()); ?>
-

Context

exception->getContext()); ?>

Headers

exception->getHeaders()); ?>
- - - -

Sorry, there has been an error. Please try again.

- - \ No newline at end of file diff --git a/source/lib/simplicity/core/error/templates/fatal.phtml b/source/lib/simplicity/core/error/handlers/http/default.phtml similarity index 51% copy from source/lib/simplicity/core/error/templates/fatal.phtml copy to source/lib/simplicity/core/error/handlers/http/default.phtml index 139d28b..edda00a 100755 --- a/source/lib/simplicity/core/error/templates/fatal.phtml +++ b/source/lib/simplicity/core/error/handlers/http/default.phtml @@ -1,21 +1,15 @@ - -mode != 'live') { ?> -

exception->getMessage(); ?>

File

exception->getFile(); ?> on line exception->getLine(); ?>

+exception instanceof smp_FatalException)) { ?> +

Trace

+
exception->getSafeTrace()); ?>
+ +

Context

exception->getContext()); ?>

Headers

-
exception->getHeaders()); ?>
- - - -

I18n()->t('error.title'); ?>

-
Textile()->convert($this->I18n()->t('error.desc')); ?>
- - - +
exception->getHeaders()); ?>
\ No newline at end of file diff --git a/source/lib/simplicity/core/error/handlers/http/http.php b/source/lib/simplicity/core/error/handlers/http/http.php new file mode 100644 index 0000000..ada3568 --- /dev/null +++ b/source/lib/simplicity/core/error/handlers/http/http.php @@ -0,0 +1,21 @@ +getException(); + + if ($e instanceof smp_HttpException) { + smp_Response::getInstance()->setStatus($e->getCode()); + } + else { + smp_Response::getInstance()->setStatus(500); + } + + + $t->exception = $this->getException(); + + smp_Response::getInstance()->setContent($t->renderTemplate()); + + } +} \ No newline at end of file diff --git a/source/lib/simplicity/core/error/handlers/json/basic.php b/source/lib/simplicity/core/error/handlers/json/basic.php new file mode 100644 index 0000000..9b50c0a --- /dev/null +++ b/source/lib/simplicity/core/error/handlers/json/basic.php @@ -0,0 +1,12 @@ +exception = $this->getException(); + + smp_Response::getInstance()->setContent($t->renderTemplate()); + smp_Response::getInstance()->setStatus(500); + } +} \ No newline at end of file diff --git a/source/lib/simplicity/core/error/templates/default.phtml b/source/lib/simplicity/core/error/templates/default.phtml index 17f0d35..8127d57 100755 --- a/source/lib/simplicity/core/error/templates/default.phtml +++ b/source/lib/simplicity/core/error/templates/default.phtml @@ -1,5 +1,3 @@ -mode != 'live') { ?> -

exception->getMessage(); ?>

File

@@ -12,10 +10,4 @@
exception->getContext()); ?>

Headers

-
exception->getHeaders()); ?>
- - - -

Sorry, there has been an error. Please try again.

- - \ No newline at end of file +
exception->getHeaders()); ?>
\ No newline at end of file diff --git a/source/lib/simplicity/core/error/templates/fatal.phtml b/source/lib/simplicity/core/error/templates/fatal.phtml index 139d28b..1a867f4 100755 --- a/source/lib/simplicity/core/error/templates/fatal.phtml +++ b/source/lib/simplicity/core/error/templates/fatal.phtml @@ -1,6 +1,3 @@ - -mode != 'live') { ?> -

exception->getMessage(); ?>

File

@@ -11,11 +8,3 @@

Headers

exception->getHeaders()); ?>
- - - -

I18n()->t('error.title'); ?>

-
Textile()->convert($this->I18n()->t('error.desc')); ?>
- - - diff --git a/source/lib/simplicity/core/template/plugin.php b/source/lib/simplicity/core/template/plugin.php new file mode 100755 index 0000000..c6aa9d2 --- /dev/null +++ b/source/lib/simplicity/core/template/plugin.php @@ -0,0 +1,32 @@ + + * @copyright Copyright (c) 2009, John Le Drew + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @version 2.0.0-alpha + * + * @smp_core + */ +abstract class smp_TemplatePlugin { + + private $_template; + + final public function __construct(smp_Template $template) + { + $this->_template = $template; + $this->init(); + } + + final protected function getTemplate() + { + return $this->_template; + } + + protected function init() {} + +} \ No newline at end of file diff --git a/source/lib/simplicity/core/template/template.php b/source/lib/simplicity/core/template/template.php new file mode 100755 index 0000000..8ae788e --- /dev/null +++ b/source/lib/simplicity/core/template/template.php @@ -0,0 +1,366 @@ + + * @copyright Copyright (c) 2009, John Le Drew + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @version 2.0.0-alpha + * + * @smp_children smp_TemplatePlugin + * @smp_core + */ +class smp_Template extends smp_Pluggable implements smp_ModuleStatic +{ + private $_data = array(); + private $_plugins = array(); + + private $_parent; + + private $_template; + private $_root; + + /** + * Constructor + * + * Create a new smp_Template instance providing the $path to the template file. Do not specify the $parent at this time, it is used for + * rendering sub templates defined by a call to render(). + * + * @param $path string + * @param $parent smp_Template + */ + public function __construct($path=null,$parent=null) + { + $this->createExtensionPoint('smp_TemplatePlugin'); + $this->registerPluginPrefix('smp_'); + + if (!($parent instanceof smp_Template)) + { + if (!file_exists($path)) { + throw new Exception("{$path} does not exist. Failed to load template."); + } + } else { + if (!file_exists($path)) $path = $parent->getRoot().$path; + if (!file_exists($path)) { + return; + } + } + + $this->_template = $path; + $this->_root = ($parent instanceof smp_Template) ? $parent->getRoot() : dirname($this->_template).DS; + + $this->_parent = $parent; + } + + public function setParent(smp_Template $parent) + { + $this->_parent = $parent; + } + + private function setRoot($path) + { + $this->_root = $path.DS; + } + + /** + * getRoot + * + * Get the root path of this template. + * + * @return string + */ + public function getRoot() + { + return $this->_root; + } + + public function getTemplate() + { + return $this->_template; + } + + /** + * set + * + * Set a value to be passed to the template. This will be accessible within + * the template as a property ($this->name). + * + * @param $name string + * @param $value mixed + */ + public function set($name,$value) + { + if ($value instanceof smp_Template) { + $value->setParent($this); + } + $this->_data[$name] = $value; + } + + /** + * get + * + * Get a value assigned to the template. + * + * @param string $name + * @return mixed + */ + public function get($name) + { + $ret = null; + + if (!isset($this->_data[$name])) return $ret; + + return $this->_data[$name]; + } + + private function &getRef($name) + { + if (($this->_parent instanceof smp_Template) && !$this->has($name)) { + return $this->_parent->getRef($name); + } + $ret = null; + + if (!isset($this->_data[$name])) return $ret; + + return $this->_data[$name]; + } + + private function &setRef($name,$value) + { + $this->_data[$name] = $value; + return $this->_data[$name]; + } + + /** + * addItem + * + * Add an items to the specified list, if the list does not exist a new list is created + * in the current template. You can also specify a key to make the list associative. + * + * @param $list string + * @param $value mixed + * @param $key string + * @return void + */ + public function addItem($list,$value,$key=null) + { + $list_ref =& $this->getRef($list); + + if (!$list_ref) { + $list_ref =& $this->setRef($list,array()); + } + + if (isset($key)) { + $list_ref[$key] = $value; + } + else { + $list_ref[] = $value; + } + } + + /** + * loadPlugin + * + * Load a specific plugin and make it available to the template. + * + * You can either provide an instance or class name. By default, + * once loaded a plugin will be available as a method of the template + * by the same name ($this->MyPlugin()), alternatively you can + * specify an identifier as the second param. + * + * @param smp_TemplatePlugin $plugin + * @param string $identifier + * @return smp_TemplatePlugin + */ + public function loadPlugin($plugin,$identifier=null) + { + if ($plugin instanceof smp_TemplatePlugin) { + $p = $plugin; + } + else + { + if (!$plugin = $this->getModuleClass($plugin)) throw new Exception("Unknown template plugin {$plugin}"); + $p = new $plugin($this); + } + + if (!isset($identifier)) { + $identifier = $this->getClassModule(get_class($p)); + } + + $this->_plugins[$identifier] = $p; + + return $this->_plugins[$identifier]; + } + + /** + * getPlugin + * + * Get an instance of a loaded plugin. + * + * @param string $name + * @return smp_TemplatePlugin + */ + public function getPlugin($name) + { + if (($this->_parent instanceof smp_Template) && !$this->hasPlugin($name)) { + return $this->_parent->getPlugin($name); + } + + if (isset($this->_plugins[$name])) + { + return $this->_plugins[$name]; + } + + return $this->loadPlugin($name); + } + + /** + * hasPlugin + * + * Return true of false in the given plugin $name exists. + * + * @param $name string + * @return boolean + */ + public function hasPlugin($name) + { + return isset($this->_plugins[$name]); + } + + /** + * @internal + */ + public function __call($name,$args) + { + return $this->getPlugin($name); + } + + /** + * Allows access to template data via a overloaded property. + * + * @internal + * @see get + */ + public function __get($name) + { + return $this->get($name); + } + + /** + * Allows you to set template data via a overloaded property. + * + * @internal + * @see set + */ + public function __set($name,$value) + { + return $this->set($name,$value); + } + + /** + * has + * + * Returns boolean true / false if the specified key is available.. + * + * @param string $name + * @return boolean + */ + public function has($name) + { + return isset($this->_data[$name]); + } + + /** + * __isset overloaded function. + * + * @internal + * @see has + * + */ + public function __isset($name) + { + return $this->has($name); + } + + /** + * render + * + * Render the template at the given path and return a string. + * + * @param string $path + * @return string + */ + public function render($path,$args=array()) + { + if (!$path) return false; + + if (!($path instanceof smp_Template)) { + if (substr($path,0,2) == './') { + $path = dirname($this->_template).DS.substr($path,2); + } + $tpl = new smp_Template($path,$this); + } + else { + $tpl = $path; + $tpl->setParent($this); + } + + foreach ($args as $k => $v) + { + $tpl->set($k,$v); + } + + return $tpl->renderTemplate(); + } + + /** + * renderTemplate + * + * Render the root template and return the resulting string. + * + * @return string + */ + public function renderTemplate() + { + if (!($this->_parent instanceof smp_Template)) + { + foreach ($this->_data as $k => $val) { + if ($val instanceof smp_Template) { + $this->_data[$k] = $this->get($k); + } + } + } + + ob_start(); + if (file_exists($this->_template)) + { + if (substr($this->_template,0,7) == 'smpa://') + { + include smp_Archive::loadFileFromArchive($this->_template,true); + } + else + { + include $this->_template; + } + + } + return ob_get_clean(); + } + + public function transferData(smp_Template $target) + { + foreach ($this->_data as $key => $value) + { + $target->set($key,$value); + unset($this->_data[$key]); + } + } + + public function e($str) + { + return htmlentities($str); + } +} \ No newline at end of file diff --git a/source/lib/simplicity/simplicity.php b/source/lib/simplicity/simplicity.php index db988d4..fddfa37 100755 --- a/source/lib/simplicity/simplicity.php +++ b/source/lib/simplicity/simplicity.php @@ -169,17 +169,18 @@ class Simplicity extends smp_Pluggable { break; } } - + } + + public function __destruct() + { if (smp_Enviroment::getInstance()->getSapi() != 'cli') { smp_Response::getInstance()->sendStatus(); smp_Response::getInstance()->sendHeaders(); } smp_Response::getInstance()->sendContent(); - - die(); } - + /** * runChain * @@ -187,7 +188,7 @@ class Simplicity extends smp_Pluggable { * * @param $chain string */ - public function runChain($chain) + public function runChain($chain,$input=array()) { if (!isset($this->_chains[$chain])) throw new smp_Exception("Chain {$chain} does not exist."); $chain = $this->_chains[$chain]; @@ -200,11 +201,13 @@ class Simplicity extends smp_Pluggable { $this->_chain = array_merge($this->_base,$this->_chain); } - $output = array(); + $output = $input; while($module = array_shift($this->_chain)) { $output = $this->runModule($module,$output); } + + return $output; } /** diff --git a/source/public/index.php b/source/public/index.php index 8459f89..6b2d5b3 100755 --- a/source/public/index.php +++ b/source/public/index.php @@ -16,5 +16,5 @@ require '../lib/simplicity/simplicity.php'; Simplicity::getInstance()->setOptions(array( - 'error_handling' => false + 'error_handling' => true ))->init()->run(); -- 2.11.4.GIT