From 86f8754c178eb4ced3cfb873e31b1835a6a8c702 Mon Sep 17 00:00:00 2001 From: Marty Wallace Date: Fri, 13 Mar 2015 11:22:32 +1100 Subject: [PATCH] 1.1.0. --- README.md | 5 ++ config.php | 11 ++++- html/{_layout.html => _layouts/doc.html} | 16 +++--- html/_layouts/main.html | 6 +++ html/_status/404.html | 8 +++ html/_status/500.html | 63 ++++++++++++++++++++++++ html/home.html | 6 ++- html/tempest/_layout.html | 52 ------------------- html/tempest/errors.html | 12 ----- sass/tempest.scss | 28 ++++++----- sass/vendor/_base.scss | 1 + server/app/App.php | 17 ++----- server/app/Responses/AdaptivePage.php | 6 ++- server/boot.php | 2 +- server/tempest/Tempest/Config.php | 14 +++--- server/tempest/Tempest/HTTP/Request.php | 8 +-- server/tempest/Tempest/Tempest.php | 47 ++++++++---------- server/tempest/Tempest/Twig/Twig.php | 14 ++++-- 18 files changed, 174 insertions(+), 142 deletions(-) rename html/{_layout.html => _layouts/doc.html} (50%) create mode 100644 html/_layouts/main.html create mode 100644 html/_status/404.html create mode 100644 html/_status/500.html delete mode 100644 html/tempest/_layout.html delete mode 100644 html/tempest/errors.html diff --git a/README.md b/README.md index 151c262..7ce09ae 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,11 @@ Tempest makes use of various tools to streamline the development process: ## Releases. +* [1.1.0](https://github.com/MartyWallace/Tempest/releases/tag/1.1.0) + * Greatly improved error handling; you can now handle specific HTTP errors buy placing a Twig template with the same name into `/html/_status/`. + * Cleant up templates. + * Cleant up SASS. + * [1.0.0](https://github.com/MartyWallace/Tempest/releases/tag/1.0.0) * Modern project structure (using `public` for public files). * Using Twig for templating. diff --git a/config.php b/config.php index b02110b..e33f74f 100644 --- a/config.php +++ b/config.php @@ -17,15 +17,22 @@ return array( '*' => array( - 'title' => 'New App', + // The application timezone. 'timezone' => 'Australia/Sydney', + // Variables that are accessible within Twig templates via {{ config. }}. + // Do not put sensitive data in this block! + 'twig' => array( + 'title' => 'New App' + ), + + // Routes that the application can respond to. 'routes' => array( '/' => 'AdaptivePage' ) ), - 'localhost' => array( + 'tempest.local' => array( // Dev mode shows more verbose errors. 'dev' => true ) diff --git a/html/_layout.html b/html/_layouts/doc.html similarity index 50% rename from html/_layout.html rename to html/_layouts/doc.html index 97a311e..ae4718a 100644 --- a/html/_layout.html +++ b/html/_layouts/doc.html @@ -1,19 +1,23 @@ - {{ title }} - Success! + {{ title is defined ? title : config.title }} - - + {% block meta %} + + {% if meta is defined %} + {% for item in meta %} + + {% endfor %} + {% endif %} + {% endblock %} {% block css %} {% endblock %} -
- {% block content %}{% endblock %} -
+ {% block body %}{% endblock %} {% block js %} diff --git a/html/_layouts/main.html b/html/_layouts/main.html new file mode 100644 index 0000000..9715fef --- /dev/null +++ b/html/_layouts/main.html @@ -0,0 +1,6 @@ +{# Append additional META tags like description here. #} +{% set meta = [ + { name: 'viewport', content: 'width=device-width, initial-scale=1' } +] %} + +{% extends '_layouts/doc.html' %} \ No newline at end of file diff --git a/html/_status/404.html b/html/_status/404.html new file mode 100644 index 0000000..e5bd6ac --- /dev/null +++ b/html/_status/404.html @@ -0,0 +1,8 @@ +{% set title = config.title ~ ' - Page Not Found' %} + +{% extends '_layouts/doc.html' %} + +{% block body %} +

404

+

This resource does not exist. Go back to our homepage.

+{% endblock %} \ No newline at end of file diff --git a/html/_status/500.html b/html/_status/500.html new file mode 100644 index 0000000..c3de779 --- /dev/null +++ b/html/_status/500.html @@ -0,0 +1,63 @@ +{% set title = config.title ~ ' - Internal Server Error' %} + +{% set meta = [ + { name: 'viewport', content: 'width=device-width, initial-scale=1' }, + { name: 'robots', context: 'noindex, nofollow' } +] %} + +{% extends '_layouts/doc.html' %} + +{% block css %} + +{% endblock %} + +{% block body %} + + +
+
+
+ {% block content %} +
    + {% for error in errors %} +
  • +
    {{ error.getString() }}
    +

    {{ error.getShortFile() }} · Line {{ error.getLine() }}

    +
  • + {% endfor %} +
+ {% endblock %} +
+
+
+

REQUEST DATA

+ +
URI
+

{{ request.value }}

+ +
GET
+
{{ request.data('get') | json_encode(constant('JSON_PRETTY_PRINT')) }}
+ +
POST
+
{{ request.data('post') | json_encode(constant('JSON_PRETTY_PRINT')) }}
+ +
NAMED
+
{{ request.data('named') | json_encode(constant('JSON_PRETTY_PRINT')) }}
+
+
+ +
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/html/home.html b/html/home.html index 855cee3..f6e9773 100644 --- a/html/home.html +++ b/html/home.html @@ -1,6 +1,8 @@ -{% extends '_layout.html' %} +{% set title = config.title ~ ' - Success!' %} -{% block content %} +{% extends '_layouts/main.html' %} + +{% block body %}

Ivan Aivazovsky - The Tempest

diff --git a/html/tempest/_layout.html b/html/tempest/_layout.html deleted file mode 100644 index 5f02776..0000000 --- a/html/tempest/_layout.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - {{ title }} - - - - - - - - - -
-
-
- {% block content %}{% endblock %} -
-
-
-

REQUEST DATA

- -
URI
-

{{ uri }}

- -
GET
-
{{ get }}
- -
POST
-
{{ post }}
- -
NAMED
-
{{ named }}
-
-
- -
-
-
- - - - \ No newline at end of file diff --git a/html/tempest/errors.html b/html/tempest/errors.html deleted file mode 100644 index b53c0b1..0000000 --- a/html/tempest/errors.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'tempest/_layout.html' %} - -{% block content %} -
    - {% for error in errors %} -
  • -
    {{ error.getString() }}
    -

    {{ error.getShortFile() }} · Line {{ error.getLine() }}

    -
  • - {% endfor %} -
-{% endblock %} \ No newline at end of file diff --git a/sass/tempest.scss b/sass/tempest.scss index 953b99c..aab5597 100644 --- a/sass/tempest.scss +++ b/sass/tempest.scss @@ -54,22 +54,24 @@ ul { list-style: none; margin: 0 auto; text-align: left; -} -ul > li + li { - border-top: 1px dotted #DADADA; - margin-top: 20px; - padding-top: 20px; -} + li { + + li { + border-top: 1px dotted #DADADA; + margin-top: 20px; + padding-top: 20px; + } -ul > li > pre { - background: none; - white-space: normal; - word-wrap: break-word; -} + pre { + background: none; + white-space: normal; + word-wrap: break-word; -ul > li > pre > code { - color: #A00; + code { + color: #A00; + } + } + } } small { diff --git a/sass/vendor/_base.scss b/sass/vendor/_base.scss index 6ef5823..271cda3 100644 --- a/sass/vendor/_base.scss +++ b/sass/vendor/_base.scss @@ -1,3 +1,4 @@ +// TODO: Get a real CSS reset in here. * { margin: 0; padding: 0; diff --git a/server/app/App.php b/server/app/App.php index d930c61..fce0321 100644 --- a/server/app/App.php +++ b/server/app/App.php @@ -2,8 +2,6 @@ use Tempest\Tempest; use Tempest\HTTP\Router; -use Tempest\HTTP\Request; -use Tempest\HTTP\Status; class App extends Tempest @@ -16,17 +14,12 @@ protected function setup(Router $router) } - protected function errorOutput(Request $r, $code) + protected function defineServices() { - if($code === Status::NOT_FOUND) - { - // You are able to implement a custom 404 page here. - return '404 - Not Found.'; - } - - - // Use default error output if the code hasn't been handled. - return parent::errorOutput($r, $code); + return array( + // Add services here. Services are accessible in Twig via {{ tempest. }}. + // ... + ); } } \ No newline at end of file diff --git a/server/app/Responses/AdaptivePage.php b/server/app/Responses/AdaptivePage.php index fff45ee..39021c0 100644 --- a/server/app/Responses/AdaptivePage.php +++ b/server/app/Responses/AdaptivePage.php @@ -19,9 +19,13 @@ public function setup(Request $r) public function index(Request $request) { + trigger_error('fdsfs'); + trigger_error('fdsfs'); + trigger_error('fdsfs'); + $result = tempest()->twig->render($this->name . '.html', array()); - if($result === null) + if ($result === null) { // NULL is provided if the template could not be loaded. tempest()->abort(404); diff --git a/server/boot.php b/server/boot.php index 3f4b411..646e302 100644 --- a/server/boot.php +++ b/server/boot.php @@ -13,6 +13,6 @@ define('POST', 'post'); define('NAMED', 'named'); -define('HOST', $_SERVER['SERVER_NAME']); +define('HOST', strtolower($_SERVER['SERVER_NAME'])); define('REQUEST_CLEAN', preg_replace('/(\?|#)(.+)/', '', $_SERVER["REQUEST_URI"])); define('REQUEST_URI', Path::create(REQUEST_CLEAN, Path::DELIMITER_LEFT)); \ No newline at end of file diff --git a/server/tempest/Tempest/Config.php b/server/tempest/Tempest/Config.php index 0054748..dbfefd8 100644 --- a/server/tempest/Tempest/Config.php +++ b/server/tempest/Tempest/Config.php @@ -15,11 +15,11 @@ public function __construct() { $data = require_once(APP_ROOT . 'config.php'); - if(array_key_exists('*', $data)) + if (array_key_exists('*', $data)) { $this->data = $data['*']; - if(array_key_exists(HOST, $data)) + if (array_key_exists(HOST, $data)) { // Consume host-specific configuration and overwrite where necessary. $this->data = array_replace_recursive($this->data, $data[HOST]); @@ -32,7 +32,7 @@ public function __construct() } // General configuration. - date_default_timezone_set($this->data("timezone", "Australia/Sydney")); + if ($this->data('timezone')) date_default_timezone_set($this->data('timezone')); } @@ -46,15 +46,15 @@ public function __construct() */ public function data($field = null, $default = null) { - if($field === null) return $this->data; + if ($field === null) return $this->data; $path = preg_split('/\.+/', $field); - if(!array_key_exists($path[0], $this->data)) return $default; + if (!array_key_exists($path[0], $this->data)) return $default; $target = $this->data; - foreach($path as $p) + foreach ($path as $p) { - if(array_key_exists($p, $target)) $target = $target[$p]; + if (array_key_exists($p, $target)) $target = $target[$p]; else return $default; } diff --git a/server/tempest/Tempest/HTTP/Request.php b/server/tempest/Tempest/HTTP/Request.php index fe68dc2..550f60b 100644 --- a/server/tempest/Tempest/HTTP/Request.php +++ b/server/tempest/Tempest/HTTP/Request.php @@ -36,8 +36,8 @@ public function data($stack = null, $key = null, $default = null) { $data = $this->getData(); - if($stack === null) return $data; - if($key === null) return $data[$stack]; + if ($stack === null) return $data; + if ($key === null) return $data[$stack]; return array_key_exists($key, $data[$stack]) ? $data[$stack][$key] : $default; } @@ -53,7 +53,7 @@ public function redirect($dest, $status = 400) { http_response_code($status); - if(preg_match('/^\w*:\/\//', $dest)) header("Location: " . $dest); + if (preg_match('/^\w*:\/\//', $dest)) header("Location: " . $dest); else header("Location: " . $dest); exit; @@ -65,7 +65,7 @@ public function redirect($dest, $status = 400) */ private function getData() { - if($this->data === null) + if ($this->data === null) { $this->data = array( GET => array_slice($_GET, 0), diff --git a/server/tempest/Tempest/Tempest.php b/server/tempest/Tempest/Tempest.php index 66830c5..c468ef1 100644 --- a/server/tempest/Tempest/Tempest.php +++ b/server/tempest/Tempest/Tempest.php @@ -7,6 +7,7 @@ use Tempest\HTTP\Response; use Tempest\MySQL\Database; use Tempest\Twig\Twig; +use Tempest\Utils\Path; /** @@ -93,15 +94,15 @@ public function start() $request = $this->router->getRequest(); $match = $this->router->getMatch(); - if($match !== null) + if ($match !== null) { // Create the response class. $responder = Responder::create(preg_replace('/\.+/', '\\', 'Responses\\' . $match->getHandlerClass()), $this); $method = $match->getHandlerMethod(); - if($responder !== null) + if ($responder !== null) { - if(method_exists($responder, $method)) + if (method_exists($responder, $method)) { $responder->setup($request); $this->setResponse($responder->finalize($responder->$method($request))); @@ -184,13 +185,13 @@ public function error($number, $string, $file, $line, $context) */ private function finalize() { - if($this->status <= 300 && count($this->errors) > 0) + if ($this->status <= 300 && count($this->errors) > 0) { // If the HTTP Responder code is in the OK range but there are errors. $this->status = Status::INTERNAL_SERVER_ERROR; } - if($this->status >= 300) + if ($this->status >= 300) { // If the HTTP Responder code does not fall in the OK range, transform the output to an alternate value. // The alternate value is defined in App::showErrors(). @@ -201,7 +202,7 @@ private function finalize() http_response_code($this->status); header("Content-Type: {$this->response->getMime()}; charset={$this->response->getCharset()}"); - if($this->response !== null) + if ($this->response !== null) { echo $this->response->getFinalOutput($this->router->getRequest()); } @@ -218,26 +219,20 @@ private function finalize() * * @return string|array|Response The resulting output. */ - protected function errorOutput(Request $request, $code) + private function errorOutput(Request $request, $code) { - if($code === Status::NOT_FOUND) + if (Path::create(APP_ROOT . 'html/_status/' . $code . '.html')->isFile()) { - return '404 - Page not found.'; - } - - if($code >= 500) - { - if($this->config('dev', false)) + if ($code >= 500 && !$this->config('dev', false)) { - // Server-side errors. - return $this->twig->render('tempest/errors.html', array( - "title" => "Application Error", - "get" => count($request->data(GET)) > 0 ? json_encode($request->data(GET), JSON_PRETTY_PRINT) : "-", - "post" => count($request->data(POST)) > 0 ? json_encode($request->data(POST), JSON_PRETTY_PRINT) : "-", - "named" => count($request->data(NAMED)) > 0 ? json_encode($request->data(NAMED), JSON_PRETTY_PRINT) : "-", - 'errors' => $this->errors - )); + // Don't show server errors unless dev mode is turned on. + return null; } + + // We can create Twig templates to render errors specific to certain HTTP status codes. + return $this->twig->render('_status/' . $code . '.html', array( + 'errors' => $this->errors + )); } return null; @@ -253,7 +248,7 @@ protected function errorOutput(Request $request, $code) */ public function __get($prop) { - if(array_key_exists($prop, $this->services)) + if (array_key_exists($prop, $this->services)) { // Returns a service with the name. return $this->services[$prop]; @@ -271,13 +266,13 @@ public function __get($prop) */ protected function setResponse($value) { - if(is_array($value)) + if (is_array($value)) { // Transform returned array into JSON. $value = new Response('application/json', json_encode($value, JSON_NUMERIC_CHECK)); } - if(!is_a($value, 'Tempest\HTTP\Response')) + if (!is_a($value, 'Tempest\HTTP\Response')) { // Transform existing output to an output object, if not already. $value = new Response('text/plain', $value); @@ -317,6 +312,6 @@ public function getServices(){ return $this->services; } * * @return string */ - public function getVersion(){ return '1.0.0'; } + public function getVersion(){ return '1.1.0'; } } \ No newline at end of file diff --git a/server/tempest/Tempest/Twig/Twig.php b/server/tempest/Tempest/Twig/Twig.php index d04ac47..963b4f7 100644 --- a/server/tempest/Tempest/Twig/Twig.php +++ b/server/tempest/Tempest/Twig/Twig.php @@ -1,6 +1,7 @@ loader = new Twig_Loader_Filesystem(array(APP_ROOT . 'html/')); - $this->environment = new Twig_Environment($this->loader); + $this->loader = new Twig_Loader_Filesystem(array( + Path::create(APP_ROOT . 'html', Path::DELIMITER_RIGHT) + )); + + $this->environment = new Twig_Environment($this->loader, array( + 'debug' => tempest()->config('dev', false) + )); } @@ -37,9 +43,9 @@ public function render($file, $context = array()) if($this->loader->exists($file)) { return new TwigResponse($this->environment->render($file, array_merge($context, array( + 'config' => tempest()->config('twig', array()), 'tempest' => tempest()->getServices(), - 'request' => tempest()->getRouter()->getRequest(), - 'title' => tempest()->config('title') + 'request' => tempest()->getRouter()->getRequest() )))); }