From 578ddbe830ec452c18dea038c8db132c93f4a4ea Mon Sep 17 00:00:00 2001 From: Awilum Date: Fri, 3 Sep 2021 22:27:21 +0300 Subject: [PATCH] feat(core): add new code base for Whoops Error handling with updated settings --- composer.json | 7 +- .../core/Middlewares/WhoopsMiddleware.php | 50 +++++++ src/flextype/core/WhoopsGuard.php | 141 ++++++++++++++++++ src/flextype/flextype.php | 38 +++-- src/flextype/settings.yaml | 24 ++- 5 files changed, 220 insertions(+), 40 deletions(-) create mode 100644 src/flextype/core/Middlewares/WhoopsMiddleware.php create mode 100644 src/flextype/core/WhoopsGuard.php diff --git a/composer.json b/composer.json index 56abadb4..c80efba8 100755 --- a/composer.json +++ b/composer.json @@ -36,8 +36,6 @@ "slim/slim": "^4.8.1", - "filp/whoops": "^2.14", - "league/event": "^2.2.0", "league/glide": "^2.0.0", @@ -56,10 +54,11 @@ "slim/psr7": "^1.4", "php-di/php-di": "^6.3.4", "php-di/slim-bridge": "^3.1.1", - "middlewares/whoops": "^2.0", "nette/neon": "^3.2", "league/commonmark": "^2.0", - "siriusphp/upload": "^3.0" + "siriusphp/upload": "^3.0", + + "filp/whoops": "^2.14" }, "suggest": { "ext-zend-opcache": "Recommended for better performance", diff --git a/src/flextype/core/Middlewares/WhoopsMiddleware.php b/src/flextype/core/Middlewares/WhoopsMiddleware.php new file mode 100644 index 00000000..b07492b6 --- /dev/null +++ b/src/flextype/core/Middlewares/WhoopsMiddleware.php @@ -0,0 +1,50 @@ +settings = $settings; + $this->handlers = $handlers; + } + + /** + * Handle the requests + * + * @param ServerRequestInterface $request + * @param RequestHandlerInterface $handler + * @return ResponseInterface + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { + $whoopsGuard = new WhoopsGuard($this->settings); + $whoopsGuard->setRequest($request); + $whoopsGuard->setHandlers($this->handlers); + $whoopsGuard->install(); + + return $handler->handle($request); + } + +} \ No newline at end of file diff --git a/src/flextype/core/WhoopsGuard.php b/src/flextype/core/WhoopsGuard.php new file mode 100644 index 00000000..92033dde --- /dev/null +++ b/src/flextype/core/WhoopsGuard.php @@ -0,0 +1,141 @@ +settings = array_merge([ + 'enable' => true, + 'editor' => '', + 'title' => '', + ], $settings); + } + + /** + * Set the server request object + * + * @param ServerRequestInterface $request + * @return void + */ + public function setRequest(ServerRequestInterface $request): void { + $this->request = $request; + } + + /** + * Set the custom handlers for whoops + * + * @param array $handlers + * @return void + */ + public function setHandlers(array $handlers): void { + $this->handlers = $handlers; + } + + /** + * Install the whoops guard object + * + * @return WhoopsRun|null + */ + public function install(): ?WhoopsRun { + if ($this->settings['enable'] === false) { + return null; + } + + // Enable PrettyPageHandler with editor options + $prettyPageHandler = new PrettyPageHandler(); + + if (empty($this->settings['editor']) === false) { + $prettyPageHandler->setEditor($this->settings['editor']); + } + + if (empty($this->settings['title']) === false) { + $prettyPageHandler->setPageTitle($this->settings['title']); + } + + // Add more information to the PrettyPageHandler + $contentCharset = ''; + if ( + method_exists($this->request, 'getContentCharset') === true && + $this->request->getContentCharset() !== null + ) { + $contentCharset = $this->request->getContentCharset(); + } + + $prettyPageHandler->addDataTable('Flextype', [ + 'Version' => Flextype::VERSION, + 'Accept Charset' => $this->request->getHeader('ACCEPT_CHARSET') ?: '', + 'Content Charset' => $contentCharset, + 'HTTP Method' => $this->request->getMethod(), + 'Path' => $this->request->getUri()->getPath(), + 'Query String' => $this->request->getUri()->getQuery() ?: '', + 'Base URL' => (string) $this->request->getUri(), + 'Scheme' => $this->request->getUri()->getScheme(), + 'Port' => $this->request->getUri()->getPort(), + 'Host' => $this->request->getUri()->getHost(), + ]); + + // Set Whoops to default exception handler + $whoops = new \Whoops\Run; + + switch ($this->settings['handler']) { + case 'json': + $whoops->pushHandler(new JsonResponseHandler()); + break; + + case 'xml': + $whoops->pushHandler(new XmlResponseHandler()); + break; + + case 'plain': + $whoops->pushHandler(new PlainTextHandler()); + break; + + case 'pretty': + default: + $whoops->pushHandler($prettyPageHandler); + break; + } + + // Enable JsonResponseHandler when request is AJAX + if (Misc::isAjaxRequest() === true){ + $whoops->pushHandler(new JsonResponseHandler()); + } + + // Add each custom handler to whoops handler stack + if (empty($this->handlers) === false) { + foreach($this->handlers as $handler) { + $whoops->pushHandler($handler); + } + } + + $whoops->register(); + + return $whoops; + } + +} \ No newline at end of file diff --git a/src/flextype/flextype.php b/src/flextype/flextype.php index ae2a2e13..e343d07d 100644 --- a/src/flextype/flextype.php +++ b/src/flextype/flextype.php @@ -16,7 +16,6 @@ use DateTimeZone; use Flextype\Entries\Entries; use Flextype\Handlers\HttpErrorHandler; use Flextype\Handlers\ShutdownHandler; -use Flextype\Media\Media; use Flextype\Parsers\Parsers; use Flextype\Serializers\Serializers; use Flextype\Tokens\Tokens; @@ -57,6 +56,7 @@ use Slim\Psr7\Factory\StreamFactory; use Slim\Psr7\Response; use Slim\Psr7\Stream; use Symfony\Component\Yaml\Yaml as SymfonyYaml; +use Flextype\Middlewares\WhoopsMiddleware; use function app; use function array_replace_recursive; @@ -87,11 +87,11 @@ use function sys_get_temp_dir; use function trim; use function var_export; -// Init Flextype Instance -// Creates $app Application and $container Container objects +// Init Flextype Instance. +// Creates $app Application and $container Container objects. flextype(); -// Add Registry Service +// Add Registry Service. container()->set('registry', registry()); // Init Flextype config (manifest and settings) @@ -108,7 +108,7 @@ $f1 = file_exists($flextypeManifestFilePath) ? filemtime($flextypeManifestFilePa $f2 = file_exists($defaultFlextypeSettingsFilePath) ? filemtime($defaultFlextypeSettingsFilePath) : ''; $f3 = file_exists($customFlextypeSettingsFilePath) ? filemtime($customFlextypeSettingsFilePath) : ''; -// Create Unique Cache ID +// Create Unique Cache ID. $cacheID = md5($flextypeManifestFilePath . $defaultFlextypeSettingsFilePath . $customFlextypeSettingsFilePath . $f1 . $f2 . $f3); if (filesystem()->file($preflightFlextypePath . '/' . $cacheID . '.php')->exists()) { @@ -194,15 +194,6 @@ if (registry()->get('flextype.settings.cache.routes')) { app()->getRouteCollector()->setCacheFile(PATH['tmp'] . '/routes/routes.php'); } -$callableResolver = app()->getCallableResolver(); -$responseFactory = app()->getResponseFactory(); -$serverRequestCreator = ServerRequestCreatorFactory::create(); -$request = $serverRequestCreator->createServerRequestFromGlobals(); - -$errorHandler = new HttpErrorHandler($callableResolver, $responseFactory); -$shutdownHandler = new ShutdownHandler($request, $errorHandler, registry()->get('flextype.settings.errors.display')); -register_shutdown_function($shutdownHandler); - // Add Session Service container()->set('session', new Session()); @@ -216,8 +207,8 @@ container()->set('emitter', new Emitter()); container()->set('slugify', new Slugify([ 'separator' => registry()->get('flextype.settings.slugify.separator'), 'lowercase' => registry()->get('flextype.settings.slugify.lowercase'), - 'trim' => registry()->get('flextype.settings.slugify.trim'), - 'regexp' => registry()->get('flextype.settings.slugify.regexp'), + 'trim' => registry()->get('flextype.settings.slugify.trim'), + 'regexp' => registry()->get('flextype.settings.slugify.regexp'), 'lowercase_after_regexp' => registry()->get('flextype.settings.slugify.lowercase_after_regexp'), 'strip_tags' => registry()->get('flextype.settings.slugify.strip_tags'), ])); @@ -395,8 +386,8 @@ container()->set('images', static function () { // Setup Glide server $server = ServerFactory::create([ 'source' => $source, - 'cache' => $cache, - 'api' => $api, + 'cache' => $cache, + 'api' => $api, ]); // Set presets @@ -482,11 +473,16 @@ if (registry()->get('flextype.settings.cors.enabled')) { // Add Routing Middleware app()->addRoutingMiddleware(); -// Add Error Handling Middleware -app()->addErrorMiddleware(registry()->get('flextype.settings.errors.display'), false, false)->setDefaultErrorHandler($errorHandler); - // Run high priority event: onFlextypeBeforeRun before Flextype Application starts. emitter()->emit('onFlextypeBeforeRun'); +// Add Whoops Error Handling Middleware +app()->add(new WhoopsMiddleware([ + 'enable' => registry()->get('flextype.settings.errors.display'), + 'editor' => registry()->get('flextype.settings.errors.editor'), + 'title' => registry()->get('flextype.settings.errors.page_title'), + 'handler' => registry()->get('flextype.settings.errors.handler'), +])); + // Run Flextype Application app()->run(); diff --git a/src/flextype/settings.yaml b/src/flextype/settings.yaml index 92f81a49..2da8e8b1 100644 --- a/src/flextype/settings.yaml +++ b/src/flextype/settings.yaml @@ -53,6 +53,15 @@ errors: # Set true to display errors. display: true + # Editor (emacs, idea, macvim, phpstorm, sublime, textmate, xdebug, vscode, atom, espresso) + editor: atom + + # Error page title + page_title: Error! + + # Handler (pretty, plain, json, xml) + handler: pretty + # Entries entries: directory: '/entries' @@ -379,22 +388,8 @@ cache: zenddisk: {} zendshm: {} -# Whoops -# -# Error handler framework for PHP. -# -# - editor: emacs, idea, macvim, phpstorm, sublime, textmate, xdebug, vscode, atom, espresso -# -# - page_title: page title -whoops: - editor: atom - page_title: Error! - # Slim # -# - display_error_details: When true, additional information about exceptions are -# displayed by the default error handler. -# # - add_content_length_header: When true, Slim will add a Content-Length header to # the response. If you are using a runtime analytics tool, # such as New Relic, then this should be disabled. @@ -413,7 +408,6 @@ whoops: # If 'append' or 'prepend', then any echo or print statements # are captured and are either appended or prepended to the Response # returned from the route callable. -display_error_details: true add_content_length_header: true router_cache_file: false determine_route_before_app_middleware: false