-
-
Notifications
You must be signed in to change notification settings - Fork 340
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
[TwigComponent] Fix usage of {% embed %} with {% block %} in <twig:> components, close #952 #1397
Conversation
I'm personnaly 👎 Main reasons:
When we'll rewrite the HTML prelexer, or the component rendering/ code generation... we don't want to deal with all Twig. As we already have not all the time to solve or improve TwigComponent / LiveComponent things. I won't fight this in anyway of course, but really i'd rather go the other way around and forbid <twig:block /> outside TwigComponent "today"... |
So what's your alternative for smoothly migrating big code-base that uses To me, blocks inside |
On this, i 100% agree. Even if "philosophically" i'm having doubt about this embed-in-template situation. But this may/should not be done by writing more code about specific template tags (again, not criticising your work on this, far from it..) but i lost so many hours trying to debug things in Twig/Live components, that i'm 100% certain if we start to code specific things about every tag construct of twig, there is a big maintanability problem... So i really do not thing we should have any code concerning "embed" in this repository. Or we should also have to handle "macro", "with"..... and "use". That beeing said, what are the alternatives right now ? I don't know :( Can this by fixing exisiting block handling ? |
Yeah I understand your point too, maybe my approach is too naive and can be optimized for others Twig tokens like
TBH I don't know, all I can say during my debug phase is that the following code (without blocks in embed): <twig:Alert>
<p>
{% embed "my_embed.html.twig" with { foo: 'bar' } %}{% endembed %}
</p>
</twig:Alert> is nicely converted to {% component 'Alert' %}
{% block content %}<p>
{% embed "my_embed.html.twig" with { foo: 'bar' } %}{% endembed %}
</p>
{% endblock %}{% endcomponent %} But this code:
raises error {% component 'Alert' %}
{% block content %}<p>
{% embed "my_embed.html.twig" %}
{% endblock %}{% block my_embed_block_1 "foo" %}
{% block my_embed_block_2 %}bar{% endblock %}
{% endembed %}
</p>
</twig:Alert> You can see a if (!empty($this->currentComponents) && $this->currentComponents[\count($this->currentComponents) - 1]['hasDefaultBlock']) {
$output .= '{% endblock %}';
$this->currentComponents[\count($this->currentComponents) - 1]['hasDefaultBlock'] = false;
} |
Yo @Kocal! We should definitely fix this. But, to be clear, I think there are 2 separate issues. I think you fixed them both at once, but I want to clarity. Issue 1: blocks without
This errors - we're simply not processing the Issue 2: the embed issue where we think blocks that are inside of the |
I think fixing the block thing in the Prelexer would fix both, no ?
In all manner (and not related to this PR) we have to refacto/improve the PreLexer soon, as we do not handle a lot of minor / edge cases |
@Kocal .. do you think you could extract this part in your code and try without any "embed" handling at first ? Or you do think both need to be fixed at once ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ok with the 2 things in on PR as long as we can get test cases to cover both individually :).
View from the mountain looks crazy to me. I ski, but on hills - never have been on a real mountain in winter!
Lexer::REGEX_NAME, | ||
'', | ||
trim(mb_substr($this->input, $prevPosition, $this->position - $prevPosition))) | ||
; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of keeping calculating the content between the positions, can we use the return value of $this->consumeUntil('%}');
?
Also, in the test, you have
{% block my_embed_block_1 "foo" %}
I can understand that, after the preg_replace()
, the ""
would remain. And so isBlockSelfClosing
would be true. But isn't this a valid syntax?
{% block my_embed_block_1 fooVariable %}
In this case, everything would be replaced, the result would be an empty string, and isBlockSelfClosing
would be false, right? Could we, instead, (A) grab the content between {% block
and %}
, trim()
the whitespace, then set isBlockSelfClosing
to true if there are ANY non-whitespace characters left?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But isn't this a valid syntax?
{% block my_embed_block_1 fooVariable %}
Indeed. (https://twig.symfony.com/doc/3.x/tags/extends.html#block-shortcuts)
{% block title page_title|title %}
(but pretty sure this is not the hardest problem we may theoretically have while mixing twig/html :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of keeping calculating the content between the positions, can we use the return value of
$this->consumeUntil('%}');
?
Hum you're right, I will give it a try.
Also, in the test, you have
{% block my_embed_block_1 "foo" %}
I can understand that, after the
preg_replace()
, the""
would remain. And soisBlockSelfClosing
would be true. But isn't this a valid syntax?
This is not true, when running the regex /[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A
on my_embed_block "foo"
, only the my_embed_block
will be removed from the string, "foo"
will still be there.
See https://regex101.com/r/LVIP6p/1.
{% block my_embed_block_1 fooVariable %}
In this case, everything would be replaced, the result would be an empty string, and
isBlockSelfClosing
would be false, right? Could we, instead, (A) grab the content between{% block
and%}
,trim()
the whitespace, then setisBlockSelfClosing
to true if there are ANY non-whitespace characters left?
Nope, fooVariable
will still be there after preg_replace
, see https://regex101.com/r/FU3VmO/1.
<twig:Alert> | ||
<p> | ||
{% embed "my_embed.html.twig" %} | ||
{% block my_embed_block_1 "foo" %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to see this tested independently, both with a string - like '"foo"- and also a variable like
{% block my_block fooVar %}`
I've applied your suggestions :)
@smnandre unfortunately removing the |
I looked a bit and it's almost perfect. But i think @weaverryan was right, and we are solving two problems at once that deserve independant solutions. Here is a new test that fails (and probably not because of your code, it was just not tested before i guess) yield 'component_where_entire_default_block_is_twig_embed_with_endblock_name' => [
<<<EOF
<twig:Alert>
<p>
{% embed "my_embed.html.twig" %}
{% block my_embed_block %}{% endblock my_embed_block %}
{% endembed %}
</p>
</twig:Alert>
EOF,
<<<EOF
{% component 'Alert' %}
{% block content %}<p>
{% embed "my_embed.html.twig" %}
{% block my_embed_block %}{% endblock my_embed_block %}
{% endembed %}
</p>
{% endblock %}{% endcomponent %}
EOF,
]; Trying to solve it, and thinking about what i suggested about the embed isolation, i realized.... we should never be in that situation in the first place :) A current component cannot have any impact on children embed content... So i think when we detect an embed we should call the prelexer (as it's done in the block parsing) But it was already there, so let's merge your fix and adress all this after :) |
Thanks for your work on this Hugo! |
You're welcome :) |
Hi everyone, this PR is an attempt to fix #952.
It fix supports for
{% block X %}foo{% endblock %}
and{% block X "foo"%}
, from{% embed %}
, in<twig:>
syntax.The following code:
is now properly converted to:
Since I'm not familiar with the
PreLexer
, let me know if a better solution/implementation exists.