diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cf7d8639..6c0b59f4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Added `Grav\Framework\Object` classes for creating collections of objects * Added `Grav\Framework\Page` interfaces * Added `|nicenumber` Twig filter + * Added `{% try %} ... {% catch %} Error: {{ e.message }} {% endcatch %}` tag to allow basic exception handling inside Twig * Deprecated GravTrait 1. [](#improved) * Make it possible to include debug bar also into non-HTML responses diff --git a/system/src/Grav/Common/Debugger.php b/system/src/Grav/Common/Debugger.php index cce279d38..40a485402 100644 --- a/system/src/Grav/Common/Debugger.php +++ b/system/src/Grav/Common/Debugger.php @@ -74,7 +74,7 @@ class Debugger */ public function enabled($state = null) { - if (isset($state)) { + if ($state !== null) { $this->enabled = $state; } @@ -92,7 +92,7 @@ class Debugger // Only add assets if Page is HTML $page = $this->grav['page']; - if ($page->templateFormat() != 'html') { + if ($page->templateFormat() !== 'html') { return $this; } @@ -107,13 +107,13 @@ class Debugger // Get the required CSS files list($css_files, $js_files) = $this->renderer->getAssets(null, JavascriptRenderer::RELATIVE_URL); - foreach ($css_files as $css) { + foreach ((array)$css_files as $css) { $assets->addCss($css); } $assets->addCss('/system/assets/debugger.css'); - foreach ($js_files as $js) { + foreach ((array)$js_files as $js) { $assets->addJs($js); } } @@ -166,7 +166,7 @@ class Debugger if ($this->enabled()) { // Only add assets if Page is HTML $page = $this->grav['page']; - if ($page->templateFormat() != 'html' || !$this->renderer) { + if (!$this->renderer || $page->templateFormat() !== 'html') { return $this; } @@ -216,7 +216,7 @@ class Debugger */ public function startTimer($name, $description = null) { - if ($name[0] == '_' || $this->enabled()) { + if ($name[0] === '_' || $this->enabled()) { $this->debugbar['time']->startMeasure($name, $description); $this->timers[] = $name; } @@ -233,7 +233,7 @@ class Debugger */ public function stopTimer($name) { - if (in_array($name, $this->timers) && ($name[0] == '_' || $this->enabled())) { + if (in_array($name, $this->timers, true) && ($name[0] === '_' || $this->enabled())) { $this->debugbar['time']->stopMeasure($name); } diff --git a/system/src/Grav/Common/Twig/TokenParserTry.php b/system/src/Grav/Common/Twig/TokenParserTry.php new file mode 100644 index 000000000..74465540f --- /dev/null +++ b/system/src/Grav/Common/Twig/TokenParserTry.php @@ -0,0 +1,66 @@ + + * {% try %} + *
  • {{ user.get('name') }}
  • + * {% catch %} + * {{ e.message }} + * {% endcatch %} + * + */ +class TokenParserTry extends \Twig_TokenParser +{ + /** + * Parses a token and returns a node. + * + * @param \Twig_Token $token A Twig_Token instance + * + * @return \Twig_NodeInterface A Twig_NodeInterface instance + */ + public function parse(\Twig_Token $token) + { + $lineno = $token->getLine(); + $stream = $this->parser->getStream(); + + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + $try = $this->parser->subparse([$this, 'decideCatch']); + $stream->next(); + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + $catch = $this->parser->subparse([$this, 'decideEnd']); + $stream->next(); + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + + return new TwigNodeTry($try, $catch, $lineno, $this->getTag()); + } + + public function decideCatch(\Twig_Token $token) + { + return $token->test(array('catch')); + } + + public function decideEnd(\Twig_Token $token) + { + return $token->test(array('endtry')) || $token->test(array('endcatch')); + } + + /** + * Gets the tag name associated with this token parser. + * + * @return string The tag name + */ + public function getTag() + { + return 'try'; + } +} diff --git a/system/src/Grav/Common/Twig/TwigExtension.php b/system/src/Grav/Common/Twig/TwigExtension.php index 5201bc71f..b1ee96da1 100644 --- a/system/src/Grav/Common/Twig/TwigExtension.php +++ b/system/src/Grav/Common/Twig/TwigExtension.php @@ -148,6 +148,16 @@ class TwigExtension extends \Twig_Extension ]; } + /** + * @return array + */ + public function getTokenParsers() + { + return [ + new TokenParserTry(), + ]; + } + /** * Filters field name by changing dot notation into array notation. * diff --git a/system/src/Grav/Common/Twig/TwigNodeTry.php b/system/src/Grav/Common/Twig/TwigNodeTry.php new file mode 100644 index 000000000..009556557 --- /dev/null +++ b/system/src/Grav/Common/Twig/TwigNodeTry.php @@ -0,0 +1,52 @@ + $try, 'catch' => $catch), array(), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param \Twig_Compiler $compiler A Twig_Compiler instance + * @throws \LogicException + */ + public function compile(\Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + + $compiler + ->write('try {') + ; + + $compiler + ->indent() + ->subcompile($this->getNode('try')) + ; + + if ($this->hasNode('catch') && null !== $this->getNode('catch')) { + $compiler + ->outdent() + ->write('} catch (\Exception $e) {' . "\n") + ->indent() + ->write('if (isset($context[\'grav\'][\'debugger\'])) $context[\'grav\'][\'debugger\']->addException($e);' . "\n") + ->write('$context[\'e\'] = $e;' . "\n") + ->subcompile($this->getNode('catch')) + ; + } + + $compiler + ->outdent() + ->write("}\n"); + } +}