-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What would you like to see as major changes that would lead to a BC break for the next major release of Twig? #3951
Comments
I really like the askama approach to make template type safe, and a little out of topic, it would be great if twig had an up-to-date formatter (maybe with a prettier plugin maintained by core team) |
I like that you started removing usage of This will allow concurrent Twig renderings using fibers. |
I would like to see a focus on component based templating over overriding/inheritance. For that macros need an improvement specifically the need to import them separately in every block. Would be great to support ux html component syntax natively for creating components. A type checker plugin (pslam/phpstan) would be nice to have as well. |
Support for step debugging via source maps would be nice. |
Plugin / Theme Structure like Shopware built around Twig. We had to built something as well and it feels bad to just copy if this could have been solved directly. And twig is already strong in multiple inheritance. |
Static type support for generated php to increase performance and predictable execution. I already tried to approach it but optimisation levels were commented as too breaking. So we could break it here. #3928 |
Still be able to use Twig without pulling a lot of more dependencies. E.g when you merge the twig symfony bridge into the twig package and in a small project just want to get some templating, you don't get the whole dependency clutter from the framework bundle. I don't use laravel/blade because you always get so much laravel stuff with it. I just want something small that can do inheritance and autoescape. Otherwise I would just use php right away. I see benefits in merging some code from expression language as twig has to parse expressions as well and has "just" some nodes on top. |
Change the null-coalescing operator to an empty- (or falsy-) coalescing operator. All the time I have a variable that is empty but not null, and I want to do EDIT: I expected some 👎🏻 reactions but I'd like to hear an explanation for them |
Some type of script block to write multiple statements without typing {% %} for every line would be nice. Something like this: {% script %}
set counter = 0;
set color = "#33b5e5";
set list_items = [{ ... }, { ... }];
if (some_var is same as true)
set list_items = [...list_items, { ... }];
endif
{% endscript %} |
Definitely two things: Removing entirely the
|
Its called the null coalescing operator for a reason. The whole php community is moving towards more strict typing, let's not create unexpected results by changing a well known concept like |
Add the possibility for global macro inheritance. Import in base template and available in all inheriting templates. Maybe a |
It's called that because that is what it does. If it did something else, it could be called something else.
Twig is not PHP. It is written in PHP, it compiles to PHP, but it is its own language with its own goals. (inb4 "Your idea would be an ’own goal!’”) I don't believe its goal is merely "Enable back-end OOP PHP experts to write 1:1 PHP code in fewer characters".
This thread is specifically about breaking changes. Anything accepted from this thread will be equally unexpected to the person who compiles an old Twig file with the new version without reading the new docs.
Shall we deprecate the Anyway, I won't say any more, this is clearly a non-starter. I don't think it should be, though. I'm full-stackish, I can write clean and pretty and strictly typed OOP PHP myself, but I don't think those same sensibilities should be uniformly applied to a template language meant to make front-end developers' lives easier. |
I agree with most of the points @75th is raising, but let me add a bit of fuel to them:
This should be in the front page of every article and documentation dedicated to Twig. Twig is not "a templating language for PHP" for a good reason: the definition does not make sense. No language can be a language for another language. I'm sure that said this way, everybody would agree that it makes no sense. Twig is a language, with compilers dedicated to be run by different runtimes (PHP, Ruby, NodeJS, browser runtimes...). And as such, it can - and must in my opinion - make its own decisions.
This should definitely raise some concern: that the ternary operator is not strict but that the nullish coallescing one is is something that it not consistent and goes against @reinierbutot "The whole [...] community is moving towards more strict typing". If one is strict, the other must be strict. If one is not, the other must not be.
Absolutely correct: @reinierbutot, if your position is "just make sure the data sent to the template is correct", then why these last years have seen more and more functions and filters added to Twig that are dedicated to manipulate and generate data instead of just outputting data? Why do the formatting filters exist? The backend knows everything required to send appropriately formatted dates or numbers or currencies or countries to the templates, so why were these formatting features added if "just make sure the data sent to the template is correct"? Why do the date creation function exist? The backend knows how to create a date and should send dates to the templates, right? I think we must not forget that a templating language main purpose is to process plain text. So, yeah, @reinierbutot, I agree with you that we must "make sure the data sent to the template is correct". But you have to admit that it is not the direction that Twig has been taking - and it is getting worse and worse everyday (eg the infamous |
In template inheritance, variables set outside blocks in child templates should have priority over these declared in base template https://blog.srsbiz.pl/2021/07/scope-of-set-in-twig-templates/ |
As someone coming from extending applications built-upon a framework I sometimes do not have the option to change the data, that I get. "Have no option" means no services in DI, no events in event dispatcher or as in "no data returned from a controller but rendered directly". There is always the vendor patching way but I try to focus on something maintainable. Example: when someone is giving me a doctrine entity for the template I just get a DateTimeInterface property, that could be not yet timezoned or formatted. And I think this is good. So when I have a data cache, the entity can be held in the cache independent to who renders the entity. Another example: Sometimes data is expressed twice. So when I display a date human readable, I have often have a structured data part, that expresses the same date but in a machine readable format. So I'd rather have the date once in the template data and be able to format it whenever I need it in whatever format I need it. This is the part, that gives me flexibility in changing templates of others. |
@JoshuaBehrens I get your point and I agree - but it says a lot about how backend are (not) specified - and mainly driven by the frameworks instead of by the requirements - and how frontend developers are left behind even today. My point is that if one says that "data sent to the template is correct", then it makes all the filters and data manipulators of Twig not legit. |
I would love the ability to statically analyze twig templates with phpstan/psalm. Twig templates are one of the remaining vulnerable parts of codebases to breaking changes and not knowing it. |
@ericmorand @75th thanks guys. So you want It does actually feel more like the Twig way. I'll be looking forward to using this new falseycoalescing operator 😂 |
@reinierbutot, well, I don't have a PHP setup ready but even in JavaScript, the behaviour of the ternary and the nullish coallescing operators are not consistent - or maybe they are but it is not obvious to me: console.log(null ?? 5); // 5
console.log(null ? 4 : 5); // 5
console.log('' ?? 5); // <empty string>
console.log('' ? 4 : 5); // 5 As you can see, |
Maybe not a BC break and even maybe discarded already, but what about allow to pass an object as context when rendering a template? |
Ohh, crap. I must confess: I didn’t realize that So, request withdrawn. (for that matter, it might have been nice to have it be |
The fact that the default default value of the default filter (wow, that sounds complicated) is - function _twig_default_filter($value, $default = '')
+ function _twig_default_filter($value, $default = null) |
Having new extension points somewhere between Parser and Lexer could facilitate Twig/LiveComponent maintenance and unlock some new features :) |
Very personal wish, but I'd love to have "private" templates (as in "not possible to override" with the multi-paths system, or extends) |
I almost forgot... those are also old wishes of mine, but i can't remember / understand why i marked them at "not doable" if set / ifsetThe equivalent of PHP
BreakAny method to "exit" while in loops, but ideally also inside blocks |
Strict typing for example using === instead of same as (faster DX) |
I'd like to be able to combine a set and if statement. {% if count = post.comments.count %}
There are {{ count }} comments.
{% endif %} instead of {% set count = post.comments.count %}
{% if count %}
There are {{ count }} comments.
{% endif %} |
I find adding properties to objects to be complicated and hard to read. I'd like to be able to add an element to an object without doing the merge, e.g. instead of {% if options.depth is not none %}
{% set options = options|merge({'depth': currentOptions.depth - 1}) %}
{% endif %}
{# update the matchingDepth for children #}
{% if options.matchingDepth is not none and options.matchingDepth > 0 %}
{% set options = options|merge({'matchingDepth': currentOptions.matchingDepth - 1}) %}
{% endif %} I'd like to be able to simply set an object property. {% set options.currentDepth = currentOptions.depth - 1 %} It'd be even better if there were a way to combine the if statement with the set {% set options.currentDepth = (currentOptions.depth) - 1 if options.depth is not none %}
{% options.depth is not none ? set options.currentDepth = (currentOptions.depth) - 1 %} Just brainstorming on the if / set, but the ability to set a single property would be really nice. |
Clearly a must have even if it's not directly linked to twig codebase ! Extending this check to twig bridge render arguments would be perfect. It's a bit off, but with sf router we have the same vulnerability when you change an arg name. How are you managing it ? |
You should be able to use |
Better support for fully qualified class names / enums / matchNow that we have enums in PHP, one of the greatest things is that we can use It would be great if we could have this in Twig as well. With erroring on compile time. For example: {% match entity.state as App\My\Enum %}
{% case Archived %}
It's archived
{% case Deleted %}
It's deleted
{% default %}
It's visible
{% endmatch %} We need to tell Twig what the type of Another example: {% if entity.state == App\My\Enum::Archived %} For this to work, we need to have a way to write fully qualified class references that don't require escaping. Escaping is what makes it very hard to find a class name. Especially when renaming or moving a class. Nobody thinks of searching for Allow FQCN referenceIf the previous is not possible, then maybe we could have a possibility to mark something as a fully qualified class name by prefixing it with something. For example the Then it could be written like: {% if value == constant(@App\My\Class) %} Now that Twig knows if something is a fully qualified class name, it can also guard (at compile time) that the class actually exists. When doing a refactor, where the class name changes, it will immediately fail on lint. Blade supports fully qualified class names, and I think that's sometimes really handy. I know Twig is not PHP. Allow backticksIf the previous is not possible, maybe we could allow backticks to write literal strings that are not escaped. This can be handy to reference a fully qualified class name and pass it to the Example: {% if value == constant(`App\My\Class`) %} This has the benefit that you can find the class by searching for the FQCN. Instead of also having to consider that it might be escaped like Created a PR to implement this in 4.0: |
#4067 |
I think this should not be done at compile time but at runtime, like the So as the lint command only compiles the templates, it won't enforce this without external statical analysis i guess. |
I think it can already be done in 3.x @smnandre with for instance a preLexer 3.x...VincentLanglet:Twig:preLexer This would avoid the need of overriding the Lexer in symfony/ux https://github.com/symfony/ux/blob/391e2502acac6ea107376877e6ccdc03119ca5f0/src/TwigComponent/src/Twig/ComponentLexer.php#L27 |
I agree here this should not be done on compile time because I may access in one template a class which at the project not exists because of 2 reasons. The template is only valid with additional dependency installed, the template is only there for backwards compatibility reasons to support different versions of another library. For such things better is that we may can improve some kind of static code analyzing to show such errors, where edge cases like this can then be ignored. |
Check out #4233 and https://github.com/alisqi/TwigStan. |
I would propose to remove implicit default values for macros. See #4010 for an example. {% macro marco(polo) %}
{{ polo }}
{% end macro %}
{{ _self.marco() }} In this example, This change makes it clearer which arguments are required, and which ones aren't. The backwards-compat break would be pretty big, however, for all macros that relies on the current behavior. Thanks to #4010, however, we could start triggering deprecation notices in 3.x. |
I made a suggestion here (#4185) of a very convenient feature for component-oriented uses of Twig, please consider it for twig 4 ❤️ |
I would like to see rendering a block take optional arguments. Often blocks are much easier to work with than macros, especially since macro scope is limited and you have to re-import related utilities. Basically, these 2 calls could be the same.
|
OK, it's not a BC break, but this has turned into a wish-list, so I'll add another. I'd like something shorter than |default(), and would probably like "??" {% for author in authors|default([]) %}
{% for author in authors?[]) %}
{% for author in authors??[]) %} |
The following is already valid and supported:
|
I looked into making Twig's test suite compatible with PHPUnit 11. And especially the new requirement that data providers must be declared static will require breaking changes to our test case classes. My attempt at preparing those breaking changes: |
Switching to not automatically pass the current context variables when using |
How about supporting I know this was marked internal many years ago #450 but in combination with tools like htmx being able to render a specific block would come in handy again, see e.g. https://github.com/sponsfreixes/jinja2-fragments Answer: it's supported via |
It's officially supported via https://github.com/twigphp/Twig/blob/3.x/src/TemplateWrapper.php#L58 |
https://twig.symfony.com/doc/3.x/tags/include.html
Reverse this, have the included templates default to nothing, everything from the current context needs to be passed explicitly. Basically, make {# no variables will be accessible #}
{% include 'template.html' only %} the default. Reasoning is, in practice this leads to an include in an include in an include in an include where the great-grandparent's context is used routinely and leading to very fragile, confusing and hard to debug templating solutions. |
Awesome proposal! For "DX experience", "with context" could be provided for those willing to shoot themselves into foot 😂 |
Making the |
What about a syntax like php's ?->, ($task?->getName())
So it would only apply the filter if the variable isn't null. |
@tacman I suggest you to open a dedicated issue for that feature request (which is not a BC break, as long as we ensure we use a non-ambiguous syntax) |
Looks like it wasn't mention here yet but creating "lazy" twig function and or filters should be easier. @GromNaN #3916 looks promising. But maybe a more simple |
Would it make sense to include all the PCRE functions as functions / filters? https://www.php.net/manual/en/ref.pcre.php Regular expressions are often needed... preg_match, preg_replace etc. In some cases these could be included in Twig as extra functionality in existing filters ( I know that all of this is pretty easy to add as custom extensions, but hopefully these could be bundled into core Twig without too much bloat, and perhaps seeking a more elegant syntax. |
See #4434 For the new |
To ease reading and add more context, could please mention |
We've started working on the next major Twig release. As announced last year, this new version will probably land under the Symfony mono-repository.
For the first time in Twig history, I'd like to fix the major issues that would be BC breaks and that we've never done.
This issue acts as a community wish list for things you want to see in the next major version that could lead to BC breaks (hint: like operators precedence).
Feel free to comment and vote.
The text was updated successfully, but these errors were encountered: