mpen
mpen

Reputation: 282875

How to define a null-coalescing operator for Twig?

I want to define the null-coalescing operator for Twig as per this RFC. That is to say I should be able to write an expression like

{{ x ?? y ?? 5 }}

Which would return x if it's defined and non-null, otherwise y if it's defined and non-null, otherwise 5.

This should not error if strict_variables is enabled.

I've started the implementation, but I don't know enough about the internals of Twig to complete it.

We can define the operator with an extension:

class Core extends \Twig_Extension {

    public function getName() {
        return 'nullcoalesce';
    }

    public function getOperators() {
        return [
            [], // I *think* these are where the unary operators go...?
            [
                '??' => array('precedence' => 20, 'class' => NullCoalesce::class, 'associativity' => \Twig_ExpressionParser::OPERATOR_LEFT),
            ]
        ];
    }
}

And then here's the operator:

class NullCoalesce extends \Twig_Node_Expression_Binary
{
    public function compile(\Twig_Compiler $compiler)
    {
        // ???
    }

    public function operator(\Twig_Compiler $compiler)
    {
        // ???
    }
}

How can I fill in those methods to get the desired result?

Upvotes: 1

Views: 495

Answers (1)

Alain
Alain

Reputation: 36954

As Twig files are compiled to PHP code, you need to tell Twig how to convert your new operator in PHP:

public function compile(\Twig_Compiler $compiler)
{
    // gives random variable name
    $var = $compiler->getVarName();

    // compiles: (($var = left) !== NULL ? $var : right)
    $compiler
       ->raw(sprintf('(($%s = ', $var))
       ->subcompile($this->getNode('left'))
       ->raw(sprintf(') !== NULL ? $%s : ', $var))
       ->subcompile($this->getNode('right'))
       ->raw(sprintf(')'))
    ;
}

public function operator(\Twig_Compiler $compiler)
{
    return $compiler->raw('');
}

Documentation is a bit poor about the subject, but there are lots of existing operators in lib/Twig/Node/Expression/Binary if somebody requires more samples.


About your comment on the way operators are stored in the extension, you're right. If you look at the initExtension method of Twig's Environment.php, you'll see:

        $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
        $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);

It would have been easier to have 2 methods in the extension, getUnaryOperators and getBinaryOperators but anyway, that's on the doc so we can't blame them for this :-).

Upvotes: 2

Related Questions