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");
+ }
+}