diff -u b/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php --- b/core/lib/Drupal/Core/Template/TwigExtension.php +++ b/core/lib/Drupal/Core/Template/TwigExtension.php @@ -137,8 +137,11 @@ */ public function getFunctions() { return [ - // This function will receive a renderable array, if an array is detected. + // This function will receive a renderable array object, if detected. new \Twig_SimpleFunction('render_var', [$this, 'renderVar']), + // This function casts a variable to bool, with special conditions for + // empty \ReadOnlyArrayObject objects. + new \Twig_SimpleFunction('to_bool', [$this, 'toBool']), // The url and path function are defined in close parallel to those found // in \Symfony\Bridge\Twig\Extension\RoutingExtension new \Twig_SimpleFunction('url', [$this, 'getUrl'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]), @@ -641,2 +644,18 @@ + /** + * Casts a variable to bool. + * + * @param mixed $arg + * The variable that needs casted to a boolean. + * + * @return mixed + * The rendered output or an Twig_Markup object. + */ + public function toBool($arg) { + if ($arg instanceof ReadOnlyArrayObject) { + return count($arg) > 0; + } + return (bool) $arg; + } + } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Template/TwigNodeVisitor.php +++ b/core/lib/Drupal/Core/Template/TwigNodeVisitor.php @@ -50,6 +50,42 @@ protected function doLeaveNode(\Twig_Node $node, \Twig_Environment $env) { $this->skipRenderVarFunction = TRUE; } } + // For if statements checking a variable, wrap the variable in a custom + // boolean cast that casts empty ReadOnlyArrayObjects as true. + elseif ($node instanceof \Twig_Node_If) { + $tests = $node->getNode('tests'); + if (!empty($tests)) { + foreach ($tests as $name => $test) { + // Covers if statements like {% if variable %}. + if ($test instanceof \Twig_Node_Expression_Name || $test instanceof \Twig_Node_Expression_GetAttr) { + $test = new \Twig_Node_Expression_Function('to_bool', new \Twig_Node([$test]), $node->getLine()); + } + // Covers if statements like {% if not variable %} + else if ($test instanceof \Twig_Node_Expression_Unary) { + $subtest = $test->getNode('node'); + if ($subtest instanceof \Twig_Node_Expression_Name || $subtest instanceof \Twig_Node_Expression_GetAttr) { + $wrapper = new \Twig_Node_Expression_Function('to_bool', new \Twig_Node([$subtest]), $node->getLine()); + $test->setNode('node', $wrapper); + } + } + // Covers if statements like {% if variable or other_variable %} + else if ($test instanceof \Twig_Node_Expression_Binary_And || $test instanceof \Twig_Node_Expression_Binary_Or) { + $left = $test->getNode('left'); + $right = $test->getNode('right'); + if ($left instanceof \Twig_Node_Expression_Name || $left instanceof \Twig_Node_Expression_GetAttr) { + $wrapper = new \Twig_Node_Expression_Function('to_bool', new \Twig_Node([$left]), $node->getLine()); + $test->setNode('left', $wrapper); + } + if ($right instanceof \Twig_Node_Expression_Name || $right instanceof \Twig_Node_Expression_GetAttr) { + $wrapper = new \Twig_Node_Expression_Function('to_bool', new \Twig_Node([$right]), $node->getLine()); + $test->setNode('right', $wrapper); + } + } + $tests->setNode($name, $test); + } + } + $node->setNode('tests', $tests); + } return $node; }