From ad84cf7ee52e62abf3b176a9f9f58b227ea00a92 Mon Sep 17 00:00:00 2001 From: sneakyvv Date: Wed, 30 Aug 2023 12:09:10 +0200 Subject: [PATCH] [TwigComponent] Fix Live embedded component with namespace --- .../LiveComponentSubscriberTest.php | 39 +++++++++++++++++++ src/TwigComponent/src/Twig/ComponentNode.php | 18 +-------- .../src/Twig/ComponentTokenParser.php | 2 +- .../src/Twig/TemplateNameParser.php | 26 +++++++++++++ 4 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 src/TwigComponent/src/Twig/TemplateNameParser.php diff --git a/src/LiveComponent/tests/Functional/EventListener/LiveComponentSubscriberTest.php b/src/LiveComponent/tests/Functional/EventListener/LiveComponentSubscriberTest.php index d13d7cf9f53..f018a1e7d54 100644 --- a/src/LiveComponent/tests/Functional/EventListener/LiveComponentSubscriberTest.php +++ b/src/LiveComponent/tests/Functional/EventListener/LiveComponentSubscriberTest.php @@ -311,6 +311,45 @@ public function testItUseBlocksFromEmbeddedContextUsingMultipleComponents(): voi ; } + public function testItUseBlocksFromEmbeddedContextUsingMultipleComponentsWithNamespacedTemplate(): void + { + $templateName = 'render_multiple_embedded_with_blocks.html.twig'; + $obscuredName = '5c474b02358c46cca3da7340cc79cc2e'; + + $this->addTemplateMap($obscuredName, $templateName); + + $dehydrated = $this->dehydrateComponent( + $this->mountComponent( + 'component2', + [ + 'data-host-template' => $obscuredName, + 'data-embedded-template-index' => self::DETERMINISTIC_ID_MULTI_2, + ] + ) + ); + + $token = null; + + $this->browser() + ->visit('/render-namespaced-template/render_multiple_embedded_with_blocks') + ->assertSuccessful() + ->assertSeeIn('#component1', 'Overridden content from component 1') + ->assertSeeIn('#component2', 'Overridden content from component 2 on same line - count: 1') + ->assertSeeIn('#component3', 'PreReRenderCalled: No') + ->use(function (Crawler $crawler) use (&$token) { + // get a valid token to use for actions + $token = $crawler->filter('div')->eq(1)->attr('data-live-csrf-value'); + }) + ->post('/_components/component2/increase', [ + 'headers' => ['X-CSRF-TOKEN' => $token], + 'body' => ['data' => json_encode(['props' => $dehydrated->getProps()])], + ]) + ->assertSuccessful() + ->assertHeaderContains('Content-Type', 'html') + ->assertSee('Overridden content from component 2 on same line - count: 2') + ; + } + public function testCanRedirectFromComponentAction(): void { $dehydrated = $this->dehydrateComponent($this->mountComponent('component2')); diff --git a/src/TwigComponent/src/Twig/ComponentNode.php b/src/TwigComponent/src/Twig/ComponentNode.php index d5f87e373c0..98d5aeff796 100644 --- a/src/TwigComponent/src/Twig/ComponentNode.php +++ b/src/TwigComponent/src/Twig/ComponentNode.php @@ -68,7 +68,7 @@ public function compile(Compiler $compiler): void ->raw('), ') ->raw($this->getAttribute('only') ? '[]' : '$context') ->raw(', ') - ->string($this->parseTemplateName($this->getAttribute('name'))) + ->string(TemplateNameParser::parse($this->getAttribute('name'))) ->raw(', ') ->raw($this->getAttribute('index')) ->raw(");\n") @@ -91,20 +91,4 @@ public function compile(Compiler $compiler): void ->raw("\n") ; } - - /** - * Copied from Twig\Loader\FilesystemLoader, and adjusted to needs for this class. - */ - private function parseTemplateName(string $name): mixed - { - if (isset($name[0]) && '@' == $name[0]) { - if (false === $pos = strpos($name, '/')) { - throw new \LogicException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); - } - - return substr($name, $pos + 1); - } - - return $name; - } } diff --git a/src/TwigComponent/src/Twig/ComponentTokenParser.php b/src/TwigComponent/src/Twig/ComponentTokenParser.php index 3e4ee3f6e5f..1f98e90b0cd 100644 --- a/src/TwigComponent/src/Twig/ComponentTokenParser.php +++ b/src/TwigComponent/src/Twig/ComponentTokenParser.php @@ -87,7 +87,7 @@ public function parse(Token $token): Node $this->parser->embedTemplate($module); // use deterministic index for the embedded template, so it can be loaded in a controlled manner - $module->setAttribute('index', $this->generateEmbeddedTemplateIndex($stream->getSourceContext()->getName(), $token->getLine())); + $module->setAttribute('index', $this->generateEmbeddedTemplateIndex(TemplateNameParser::parse($stream->getSourceContext()->getName()), $token->getLine())); $stream->expect(Token::BLOCK_END_TYPE); diff --git a/src/TwigComponent/src/Twig/TemplateNameParser.php b/src/TwigComponent/src/Twig/TemplateNameParser.php new file mode 100644 index 00000000000..e87ed296026 --- /dev/null +++ b/src/TwigComponent/src/Twig/TemplateNameParser.php @@ -0,0 +1,26 @@ +