Skip to content

Conversation

@shokhaa
Copy link

@shokhaa shokhaa commented Mar 28, 2025

This PR adds support for the optional chaining operator (?.) to Twig.

The optional chaining operator (?.) enables developers to read the value of a property
located deep within a chain of connected objects without having to check that each
reference in the chain is valid.

Example usage:

{{ foo?.bar?.baz }}

This is equivalent to:

{{ foo.bar.baz is defined ? foo.bar.baz }}`

@shokhaa
Copy link
Author

shokhaa commented Mar 28, 2025

./vendor/bin/simple-phpunit tests/Extension/OptionalChainingTest.php

Testing Twig\Tests\Extension\OptionalChainingTest
......S 7 / 7 (100%)

Time: 00:00.036, Memory: 10.00 MB

Copy link
Member

@stof stof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to run the bin/generate_operators_precedence.php script to regenerate the list of operators in the documentation to include your new operator.

)
) {

return new MacroReferenceExpression(new TemplateVariable($expr->getAttribute('name'), $expr->getTemplateLine()), 'macro_'.$attribute->getAttribute('value'), $arguments, $expr->getTemplateLine());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to ignore the fact that this is an optional chain. Is it expected ?


// all literals
new LiteralExpressionParser(),
new OptionalChainExpressionParser(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be registered near other get attribute operators, not in the section labelled as all literals

public const REGEX_INLINE_COMMENT = '/#[^\n]*/A';
public const PUNCTUATION = '()[]{}?:.,|';


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be reverted

}

parent::__construct($nodes, ['type' => $type, 'ignore_strict_check' => false, 'optimizable' => true], $lineno);
parent::__construct($nodes, ['type' => $type, 'ignore_strict_check' => false, 'optimizable' => true, 'is_optional_chain' => $isOptionalChain], $lineno);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need another attribute for the optional chain ? Couldn't it be a matter of the ignore_strict_check attribute ?

$compiler->raw(', ')
->repr($this->getAttribute('type'))
->raw(', ')->repr($this->definedTest)
->raw(', ')->repr($this->definedTest ?? false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change ?

$compiler->raw(')');
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this empty line between methods should not be removed


use Twig\Test\IntegrationTestCase;

class OptionalChainingTest extends IntegrationTestCase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no OptionalChaining extension. The operator is registered by CoreExtension. This should be tested by the existing integration tests by putting the fixtures in the existing folder.

@Bilge
Copy link

Bilge commented Jul 21, 2025

So we doing this or nah?

@ruudk
Copy link
Contributor

ruudk commented Aug 29, 2025

@fabpot What do you think of this idea? Today I had again a situation where this would have helped tremendously by doing something like {% if app.user.account.id == some.other.id %} and account being null.

@ryanleichty
Copy link

I'm dying for optional chaining in twig 🥵

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

6 participants