Skip to content

Commit d3ce11f

Browse files
committed
bug #1199 [TwigComponent] Fix twig:lint bug with anonymous component tag (smnandre)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [TwigComponent] Fix twig:lint bug with anonymous component tag | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | Tickets | Fix #1089 | License | MIT Sincerely i'm not sure how to handle this properly "today".. There is a lot of things i'd like to refactor in a future version, and the fact than auto-closing tags and classic ones are handled by two entirely different processes is at the top of my todo :) But right now, i'm not sure we can do better than a quick patch, allowing the "lint:twig" to not crash for anonymous <twig:Foo></twig:Foo> tags. Timeline of what "bugs": - the lint:twig command find all templates, and for each one create an empty template loader, then parse & compile the template - during the parsing, the ComponentParser calls [ComponentFactory::metadataFor](https://github.com/symfony/ux/blob/46d0b6885830b8cf546cd2c2479be2024f154ed3/src/TwigComponent/src/Twig/ComponentTokenParser.php#L50) to find the template matching the component name - if no class-based component matches, the ComponentFactory calls the the [ComponentTemplateFinder](https://github.com/symfony/ux/blob/2.x/src/TwigComponent/src/ComponentTemplateFinder.php) - the ComponentTemplateFinder then asks the Loader if a matching template exists - but as the Loader is temporary "empty".... 🐞 So we must ether: - A) stop resolving template during the parser/compiler work - B) ensure the TemplateFinder always contains the real "full" loader - C) change the way the lint:twig command works A is my long-term objective, but clearly not "today". C is not so easy, as the corresponding code is hidden between 3 private methods So.... first suggestion (dirty but working) Commits ------- 632954e [TwigComponent] Fix twig:lint bug with anonymous component tag
2 parents d27916b + 632954e commit d3ce11f

File tree

3 files changed

+34
-15
lines changed

3 files changed

+34
-15
lines changed

src/TwigComponent/src/ComponentTemplateFinder.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,32 @@
1212
namespace Symfony\UX\TwigComponent;
1313

1414
use Twig\Environment;
15+
use Twig\Loader\LoaderInterface;
1516

1617
/**
1718
* @author Matheo Daninos <matheo.daninos@gmail.com>
1819
*/
1920
final class ComponentTemplateFinder implements ComponentTemplateFinderInterface
2021
{
22+
private readonly LoaderInterface $loader;
23+
2124
public function __construct(
22-
private Environment $environment,
25+
Environment|LoaderInterface $loader,
2326
private readonly ?string $directory = null,
2427
) {
28+
if ($loader instanceof Environment) {
29+
trigger_deprecation('symfony/ux-twig-component', '2.13', 'The "%s()" method will require "%s $loader" as first argument in 3.0. Passing an "Environment" instance is deprecated.', __METHOD__, LoaderInterface::class);
30+
$loader = $loader->getLoader();
31+
}
32+
$this->loader = $loader;
2533
if (null === $this->directory) {
2634
trigger_deprecation('symfony/ux-twig-component', '2.13', 'The "%s()" method will require "string $directory" argument in 3.0. Not defining it or passing null is deprecated.', __METHOD__);
2735
}
2836
}
2937

3038
public function findAnonymousComponentTemplate(string $name): ?string
3139
{
32-
$loader = $this->environment->getLoader();
40+
$loader = $this->loader;
3341
$componentPath = rtrim(str_replace(':', '/', $name));
3442

3543
// Legacy auto-naming rules < 2.13

src/TwigComponent/src/DependencyInjection/TwigComponentExtension.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,9 @@ public function load(array $configs, ContainerBuilder $container): void
6565

6666
$container->register('ux.twig_component.component_template_finder', ComponentTemplateFinder::class)
6767
->setArguments([
68-
new Reference('twig'),
68+
new Reference('twig.loader'),
6969
$config['anonymous_template_directory'],
70-
])
71-
;
72-
70+
]);
7371
$container->setAlias(ComponentRendererInterface::class, 'ux.twig_component.component_renderer');
7472

7573
$container->registerAttributeForAutoconfiguration(
@@ -101,8 +99,6 @@ class_exists(AbstractArgument::class) ? new AbstractArgument(sprintf('Added in %
10199
])
102100
;
103101

104-
$container->register(ComponentTemplateFinder::class, 'ux.twig_component.component_template_finder');
105-
106102
$container->register('ux.twig_component.twig.component_extension', ComponentExtension::class)
107103
->addTag('twig.extension')
108104
->addTag('container.service_subscriber', ['key' => ComponentRenderer::class, 'id' => 'ux.twig_component.component_renderer'])

src/TwigComponent/tests/Unit/ComponentTemplateFinderTest.php

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\UX\TwigComponent\ComponentTemplateFinder;
1717
use Twig\Environment;
1818
use Twig\Loader\ArrayLoader;
19+
use Twig\Loader\LoaderInterface;
1920

2021
/**
2122
* @author Simon André <smn.andre@gmail.com>
@@ -36,8 +37,8 @@ public function testFindTemplate(): void
3637
'components/b.html.twig',
3738
'components/c',
3839
];
39-
$environment = $this->createEnvironment($templates);
40-
$finder = new ComponentTemplateFinder($environment, 'components');
40+
$loader = $this->createLoader($templates);
41+
$finder = new ComponentTemplateFinder($loader, 'components');
4142

4243
$this->assertEquals('components/aa.html.twig', $finder->findAnonymousComponentTemplate('aa'));
4344
$this->assertEquals('components/aa/bb.html.twig', $finder->findAnonymousComponentTemplate('aa:bb'));
@@ -84,6 +85,17 @@ public function testFindTemplateWithLegacyAutonaming(): void
8485
$this->assertNull($finder->findAnonymousComponentTemplate('nope:bar'));
8586
}
8687

88+
/**
89+
* @group legacy
90+
*/
91+
public function testTriggerDeprecationWhenEnvironmentAsFirstArgument(): void
92+
{
93+
$environment = $this->createEnvironment([]);
94+
95+
$this->expectDeprecation('Since symfony/ux-twig-component 2.13: The "Symfony\UX\TwigComponent\ComponentTemplateFinder::__construct()" method will require "Twig\Loader\LoaderInterface $loader" as first argument in 3.0. Passing an "Environment" instance is deprecated.');
96+
$finder = new ComponentTemplateFinder($environment, 'foo');
97+
}
98+
8799
/**
88100
* @group legacy
89101
*/
@@ -106,18 +118,21 @@ public function testFindTemplateWithinDirectory(): void
106118
'bar/foo/bar.html.twig',
107119
'foo/foo/bar.html.twig',
108120
];
109-
$environment = $this->createEnvironment($templates);
110-
$finder = new ComponentTemplateFinder($environment, 'foo');
121+
$loader = $this->createLoader($templates);
122+
$finder = new ComponentTemplateFinder($loader, 'foo');
111123

112124
$this->assertEquals('foo/bar.html.twig', $finder->findAnonymousComponentTemplate('bar'));
113125
$this->assertEquals('foo/foo/bar.html.twig', $finder->findAnonymousComponentTemplate('foo:bar'));
114126
$this->assertEquals('foo/foo/bar.html.twig', $finder->findAnonymousComponentTemplate('foo:bar'));
115127
}
116128

117-
private function createEnvironment(array $templates): Environment
129+
private function createLoader(array $templates): LoaderInterface
118130
{
119-
$loader = new ArrayLoader(array_combine($templates, $templates));
131+
return new ArrayLoader(array_combine($templates, $templates));
132+
}
120133

121-
return new Environment($loader);
134+
private function createEnvironment(array $templates): Environment
135+
{
136+
return new Environment($this->createLoader($templates));
122137
}
123138
}

0 commit comments

Comments
 (0)