diff --git a/src/TwigComponent/src/Twig/ComponentTokenParser.php b/src/TwigComponent/src/Twig/ComponentTokenParser.php index ff072124e41..ec543ee70e2 100644 --- a/src/TwigComponent/src/Twig/ComponentTokenParser.php +++ b/src/TwigComponent/src/Twig/ComponentTokenParser.php @@ -12,6 +12,7 @@ namespace Symfony\UX\TwigComponent\Twig; use Symfony\UX\TwigComponent\BlockStack; +use Twig\Error\SyntaxError; use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; @@ -33,6 +34,7 @@ final class ComponentTokenParser extends AbstractTokenParser public function parse(Token $token): Node { $stream = $this->parser->getStream(); + if (method_exists($this->parser, 'parseExpression')) { // Since Twig 3.21 $componentName = $this->componentName($this->parser->parseExpression()); @@ -40,6 +42,10 @@ public function parse(Token $token): Node $componentName = $this->componentName($this->parser->getExpressionParser()->parseExpression()); } + if (null === $componentName) { + throw new SyntaxError('Could not parse component name.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); + } + [$propsExpression, $only] = $this->parseArguments(); // Write a fake: "extends __parent__" into the "embedded" template. @@ -80,7 +86,7 @@ public function getTag(): string return 'component'; } - private function componentName(AbstractExpression $expression): string + private function componentName(AbstractExpression $expression): ?string { if ($expression instanceof ConstantExpression) { // using {% component 'name' %} return $expression->getAttribute('value'); @@ -90,7 +96,7 @@ private function componentName(AbstractExpression $expression): string return $expression->getAttribute('name'); } - throw new \LogicException('Could not parse component name.'); + return null; } /** diff --git a/src/TwigComponent/tests/Integration/Twig/ComponentParserTest.php b/src/TwigComponent/tests/Integration/Twig/ComponentParserTest.php index 476ee4f24df..c5799440a13 100644 --- a/src/TwigComponent/tests/Integration/Twig/ComponentParserTest.php +++ b/src/TwigComponent/tests/Integration/Twig/ComponentParserTest.php @@ -13,6 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Twig\Environment; +use Twig\Error\SyntaxError; use Twig\Loader\ArrayLoader; use Twig\TemplateWrapper; @@ -28,12 +29,12 @@ final class ComponentParserTest extends KernelTestCase */ public function testAcceptTwigComponentTagWithValidComponentName(string $name): void { - $environment = self::createEnvironment(); + $environment = $this->createEnvironment(); $source = str_replace('XXX', $name, "{% component 'XXX' %}{% endcomponent %}"); $template = $environment->createTemplate($source); - self::assertInstanceOf(TemplateWrapper::class, $template); + $this->assertInstanceOf(TemplateWrapper::class, $template); } /** @@ -41,12 +42,12 @@ public function testAcceptTwigComponentTagWithValidComponentName(string $name): */ public function testAcceptHtmlComponentTagWithValidComponentName(string $name): void { - $environment = self::createEnvironment(); + $environment = $this->createEnvironment(); $source = \sprintf('', $name, $name); $template = $environment->createTemplate($source); - self::assertInstanceOf(TemplateWrapper::class, $template); + $this->assertInstanceOf(TemplateWrapper::class, $template); } /** @@ -54,12 +55,24 @@ public function testAcceptHtmlComponentTagWithValidComponentName(string $name): */ public function testAcceptHtmlSelfClosingComponentTagWithValidComponentName(string $name): void { - $environment = self::createEnvironment(); + $environment = $this->createEnvironment(); $source = \sprintf('', $name); $template = $environment->createTemplate($source); - self::assertInstanceOf(TemplateWrapper::class, $template); + $this->assertInstanceOf(TemplateWrapper::class, $template); + } + + public function testItThrowsWhenComponentNameCannotBeParsed(): void + { + $environment = $this->createEnvironment(); + $source = '{% component [] %}{% endcomponent %}'; + + $this->expectException(SyntaxError::class); + $this->expectExceptionMessage('Could not parse component name in "foo.html.twig'); + $this->expectExceptionMessage(')" at line 1.'); + + $environment->createTemplate($source, 'foo.html.twig'); } public static function provideValidComponentNames(): iterable