diff --git a/README.md b/README.md index 209937b0..73f0d2f2 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Features - [x] Save to DB with Db Writer Adapter. - [x] Log Exception (dispatch.error and render.error) and PHP Errors in all events process. - [x] Support excludes [PHP E_* Error](http://www.php.net/manual/en/errorfunc.constants.php) (eg: exclude E_USER_DEPRECATED) in config settings. +- [x] Support excludes [PHP Exception](http://php.net/manual/en/spl.exceptions.php) (eg: Exception class or classes that extends it) in config settings. - [x] Handle only once log error for same error per configured time range. - [x] Set default page (web access) or default message (console access) for error if configured 'display_errors' = 0. - [x] Set default content when request is XMLHttpRequest via 'ajax' configuration. @@ -187,6 +188,11 @@ return [ E_USER_DEPRECATED, ], + // excluded exceptions + 'exclude-exceptions' => [ + \App\Exception\MyException::class, // can be an Exception class or class extends Exception class + ], + // show or not error 'display_errors' => 0, diff --git a/config/error-hero-module.local.php.dist b/config/error-hero-module.local.php.dist index c6bcf999..d8ea2e8c 100644 --- a/config/error-hero-module.local.php.dist +++ b/config/error-hero-module.local.php.dist @@ -50,6 +50,11 @@ return [ E_USER_DEPRECATED ], + // excluded exceptions + 'exclude-exceptions' => [ + \Application\Exception\MyException::class, // can be an Exception class or class extends Exception class + ], + // show or not error 'display_errors' => 0, diff --git a/config/expressive-error-hero-module.local.php.dist b/config/expressive-error-hero-module.local.php.dist index f75312ee..2846c710 100644 --- a/config/expressive-error-hero-module.local.php.dist +++ b/config/expressive-error-hero-module.local.php.dist @@ -48,6 +48,11 @@ return [ E_USER_DEPRECATED ], + // excluded exceptions + 'exclude-exceptions' => [ + \App\Exception\MyException::class, // can be an Exception class or class extends Exception class + ], + // show or not error 'display_errors' => 0, diff --git a/spec/Listener/MvcSpec.php b/spec/Listener/MvcSpec.php index 16622b4c..cc966094 100644 --- a/spec/Listener/MvcSpec.php +++ b/spec/Listener/MvcSpec.php @@ -260,6 +260,82 @@ }); + it('do not call logging->handleErrorException() if $e->getParam("exception") and has excluded exception match', function () { + + $config = [ + 'enable' => true, + 'display-settings' => [ + + // excluded php errors + 'exclude-php-errors' => [ + E_USER_DEPRECATED + ], + + // excluded exceptions + 'exclude-exceptions' => [ + \Exception::class, // can be an Exception class or class extends Exception class + ], + + // show or not error + 'display_errors' => 1, + + // if enable and display_errors = 0, the page will bring layout and view + 'template' => [ + 'layout' => 'layout/layout', + 'view' => 'error-hero-module/error-default' + ], + + // if enable and display_errors = 0, the console will bring message + 'console' => [ + 'message' => 'We have encountered a problem and we can not fulfill your request. An error report has been generated and sent to the support team and someone will attend to this problem urgently. Please try again later. Thank you for your patience.', + ], + + ], + 'logging-settings' => [ + 'same-error-log-time-range' => 86400, + ], + 'email-notification-settings' => [ + // set to true to activate email notification on log error + 'enable' => false, + + // Zend\Mail\Message instance registered at service manager + 'mail-message' => 'YourMailMessageService', + + // Zend\Mail\Transport\TransportInterface instance registered at service manager + 'mail-transport' => 'YourMailTransportService', + + // email sender + 'email-from' => 'Sender Name ', + + 'email-to-send' => [ + 'developer1@foo.com', + 'developer2@foo.com', + ], + ], + ]; + + $logging = Double::instance([ + 'extends' => Logging::class, + 'methods' => '__construct' + ]); + + $renderer = Double::instance(['extends' => PhpRenderer::class, 'methods' => '__construct']); + + $listener = new Mvc( + $config, + $logging, + $renderer + ); + + $exception = new \Exception('message'); + + $mvcEvent = Double::instance(['extends' => MvcEvent::class, 'methods' => '__construct']); + allow($mvcEvent)->toReceive('getParam')->andReturn($exception); + expect($listener->exceptionError($mvcEvent))->toBeNull(); + expect($logging)->not->toReceive('handleErrorException'); + + }); + }); describe('->execOnShutdown()', function () { diff --git a/spec/Middleware/ExpressiveSpec.php b/spec/Middleware/ExpressiveSpec.php index 0d57983e..12aebce4 100644 --- a/spec/Middleware/ExpressiveSpec.php +++ b/spec/Middleware/ExpressiveSpec.php @@ -496,6 +496,101 @@ }); + describe('->exceptionError()', function () { + + it('do not call logging->handleErrorException() if $e->getParam("exception") and has excluded exception match', function () { + + $config = $this->config; + $config['display-settings']['exclude-exceptions'] = [ + \Exception::class + ]; + $exception = new \Exception('message'); + + $dbAdapter = new Adapter([ + 'username' => 'root', + 'password' => '', + 'driver' => 'Pdo', + 'dsn' => 'mysql:dbname=errorheromodule;host=127.0.0.1', + 'driver_options' => [ + \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'', + ], + ]); + + $writer = new DbWriter( + [ + 'db' => $dbAdapter, + 'table' => 'log', + 'column' => [ + 'timestamp' => 'date', + 'priority' => 'type', + 'message' => 'event', + 'extra' => [ + 'url' => 'url', + 'file' => 'file', + 'line' => 'line', + 'error_type' => 'error_type', + 'trace' => 'trace', + 'request_data' => 'request_data', + ], + ], + ] + ); + + $logger = new Logger(); + $logger->addWriter($writer); + $logWritersConfig = [ + + [ + 'name' => 'db', + 'options' => [ + 'db' => 'Zend\Db\Adapter\Adapter', + 'table' => 'log', + 'column' => [ + 'timestamp' => 'date', + 'priority' => 'type', + 'message' => 'event', + 'extra' => [ + 'url' => 'url', + 'file' => 'file', + 'line' => 'line', + 'error_type' => 'error_type', + 'trace' => 'trace', + 'request_data' => 'request_data', + ], + ], + ], + ], + + ]; + + $logging = new Logging( + $logger, + 'http://serverUrl', + null, + '/', + $config, + $logWritersConfig, + null, + null + ); + + $request = new ServerRequest(); + $request = $request->withHeader('X-Requested-With', 'XmlHttpRequest'); + $response = new Response(); + $next = function ($request, $response) use ($exception) { + throw $exception; + }; + $middleware = new Expressive($config, $logging, $this->renderer); + $closure = function () use ($middleware, $request, $response, $next) { + $middleware->__invoke($request, $response, $next); + }; + expect($closure)->toThrow(new \Exception('message')); + expect($logging)->not->toReceive('handleErrorException'); + + }); + + }); + describe('->phpErrorHandler()', function () { it('do not has error', function () { diff --git a/src/Listener/Mvc.php b/src/Listener/Mvc.php index 27d472e3..839b0369 100644 --- a/src/Listener/Mvc.php +++ b/src/Listener/Mvc.php @@ -86,6 +86,13 @@ public function exceptionError(Event $e) return; } + $exceptionClass = get_class($exception); + if (isset($this->errorHeroModuleConfig['display-settings']['exclude-exceptions']) && + in_array($exceptionClass, $this->errorHeroModuleConfig['display-settings']['exclude-exceptions'])) { + // rely on original mvc process + return; + } + $this->logging->handleErrorException( $exception ); diff --git a/src/Middleware/Expressive.php b/src/Middleware/Expressive.php index 46fe0030..30ea0dbc 100644 --- a/src/Middleware/Expressive.php +++ b/src/Middleware/Expressive.php @@ -81,6 +81,13 @@ public function phpError() */ public function exceptionError($e, $request) { + $exceptionClass = get_class($e); + if (isset($this->errorHeroModuleConfig['display-settings']['exclude-exceptions']) && + in_array($exceptionClass, $this->errorHeroModuleConfig['display-settings']['exclude-exceptions']) + ) { + throw $e; + } + $this->logging->handleErrorException( $e );