Skip to content

Commit 78a5a01

Browse files
committed
[TwigComponent] Collect mount metadata in Compiler Pass
* collection mount metadata (premount, mount, postmount) in compiler pass * store in ComponentMetadata object * start removing methods from AsTwigComponent
1 parent 4485581 commit 78a5a01

File tree

16 files changed

+93
-187
lines changed

16 files changed

+93
-187
lines changed

src/TwigComponent/src/Attribute/AsTwigComponent.php

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -75,53 +75,15 @@ public function serviceConfig(): array
7575
];
7676
}
7777

78-
/**
79-
* @param object|class-string $component
80-
*
81-
* @internal
82-
*/
83-
public static function mountMethod(object|string $component): ?\ReflectionMethod
84-
{
85-
foreach ((new \ReflectionClass($component))->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
86-
if ('mount' === $method->getName()) {
87-
return $method;
88-
}
89-
}
90-
91-
return null;
92-
}
93-
94-
/**
95-
* @param object|class-string $component
96-
*
97-
* @return \ReflectionMethod[]
98-
*
99-
* @internal
100-
*/
101-
public static function postMountMethods(object|string $component): array
102-
{
103-
return self::attributeMethodsByPriorityFor($component, PostMount::class);
104-
}
105-
106-
/**
107-
* @param object|class-string $component
108-
*
109-
* @return \ReflectionMethod[]
110-
*
111-
* @internal
112-
*/
113-
public static function preMountMethods(object|string $component): array
114-
{
115-
return self::attributeMethodsByPriorityFor($component, PreMount::class);
116-
}
117-
11878
/**
11979
* @param object|class-string $component
12080
* @param class-string $attributeClass
12181
*
12282
* @return \ReflectionMethod[]
12383
*
12484
* @internal
85+
*
86+
* @deprecated since 2.22 - to be removed in 3.0
12587
*/
12688
protected static function attributeMethodsByPriorityFor(object|string $component, string $attributeClass): array
12789
{
@@ -138,6 +100,8 @@ protected static function attributeMethodsByPriorityFor(object|string $component
138100
* @return \Traversable<\ReflectionMethod>
139101
*
140102
* @internal
103+
*
104+
* @deprecated since 2.22 - to be removed in 3.0
141105
*/
142106
protected static function attributeMethodsFor(string $attribute, object|string $component): \Traversable
143107
{

src/TwigComponent/src/Command/TwigComponentDebugCommand.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use Symfony\Component\Console\Output\OutputInterface;
2222
use Symfony\Component\Console\Style\SymfonyStyle;
2323
use Symfony\Component\Finder\Finder;
24-
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
2524
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;
2625
use Symfony\UX\TwigComponent\ComponentFactory;
2726
use Symfony\UX\TwigComponent\ComponentMetadata;
@@ -214,7 +213,7 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void
214213
]);
215214

216215
// Anonymous Component
217-
if (null === $metadata->get('class')) {
216+
if ($metadata->isAnonymous()) {
218217
$table->addRows([
219218
['Type', '<comment>Anonymous</comment>'],
220219
new TableSeparator(),
@@ -229,7 +228,7 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void
229228
['Type', $metadata->get('live') ? '<info>Live</info>' : ''],
230229
new TableSeparator(),
231230
// ['Attributes Var', $metadata->get('attributes_var')],
232-
['Public Props', $metadata->get('expose_public_props') ? 'Yes' : 'No'],
231+
['Public Props', $metadata->isPublicPropsExposed() ? 'Yes' : 'No'],
233232
['Properties', implode("\n", $this->getComponentProperties($metadata))],
234233
]);
235234

@@ -242,14 +241,15 @@ private function displayComponentDetails(SymfonyStyle $io, string $name): void
242241
return \sprintf('%s(%s)', $m->getName(), implode(', ', $params));
243242
};
244243
$hooks = [];
245-
if ($method = AsTwigComponent::mountMethod($metadata->getClass())) {
246-
$hooks[] = ['Mount', $logMethod($method)];
244+
$reflector = new \ReflectionClass($metadata->getClass());
245+
foreach ($metadata->getPreMounts() as $method) {
246+
$hooks[] = ['PreMount', $logMethod($reflector->getMethod($method))];
247247
}
248-
foreach (AsTwigComponent::preMountMethods($metadata->getClass()) as $method) {
249-
$hooks[] = ['PreMount', $logMethod($method)];
248+
foreach ($metadata->getMounts() as $method) {
249+
$hooks[] = ['Mount', $logMethod($reflector->getMethod($method))];
250250
}
251-
foreach (AsTwigComponent::postMountMethods($metadata->getClass()) as $method) {
252-
$hooks[] = ['PostMount', $logMethod($method)];
251+
foreach ($metadata->getPostMounts() as $method) {
252+
$hooks[] = ['PostMount', $logMethod($reflector->getMethod($method))];
253253
}
254254
if ($hooks) {
255255
$table->addRows([

src/TwigComponent/src/ComponentFactory.php

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@
2525
*/
2626
final class ComponentFactory implements ResetInterface
2727
{
28-
private static $mountMethods = [];
28+
private static array $mountMethods = [];
2929

3030
/**
3131
* @param array<string, array> $config
3232
* @param array<class-string, string> $classMap
33+
* @param array<class-string, array<string, string[]> $classMounts
3334
*/
3435
public function __construct(
3536
private ComponentTemplateFinderInterface $componentTemplateFinder,
@@ -89,7 +90,7 @@ public function mountFromObject(object $component, array $data, ComponentMetadat
8990
$originalData = $data;
9091
$data = $this->preMount($component, $data, $componentMetadata);
9192

92-
$this->mount($component, $data);
93+
$this->mount($component, $data, $componentMetadata);
9394

9495
// set data that wasn't set in mount on the component directly
9596
foreach ($data as $property => $value) {
@@ -141,20 +142,20 @@ public function get(string $name): object
141142
return $this->components->get($metadata->getName());
142143
}
143144

144-
private function mount(object $component, array &$data): void
145+
private function mount(object $component, array &$data, ComponentMetadata $componentMetadata): void
145146
{
146147
if ($component instanceof AnonymousComponent) {
147148
$component->mount($data);
148149

149150
return;
150151
}
151-
152-
if (!($this->config[$component::class]['mount'] ?? false)) {
152+
153+
if (!$componentMetadata->getMounts()) {
153154
return;
154155
}
155-
156+
156157
$mount = self::$mountMethods[$component::class] ??= (new \ReflectionClass($component))->getMethod('mount');
157-
158+
158159
$parameters = [];
159160
foreach ($mount->getParameters() as $refParameter) {
160161
if (\array_key_exists($name = $refParameter->getName(), $data)) {
@@ -177,11 +178,9 @@ private function preMount(object $component, array $data, ComponentMetadata $com
177178
$this->eventDispatcher->dispatch($event);
178179
$data = $event->getData();
179180

180-
if ($preMounts = $this->config[$component::class]['preMount'] ?? []) {
181-
foreach ($preMounts as $preMount) {
182-
if (null !== $newData = $component->$preMount($data)) {
183-
$data = $newData;
184-
}
181+
foreach ($componentMetadata->getPreMounts() as $preMount) {
182+
if (null !== $newData = $component->$preMount($data)) {
183+
$data = $newData;
185184
}
186185
}
187186

@@ -197,11 +196,9 @@ private function postMount(object $component, array $data, ComponentMetadata $co
197196
$this->eventDispatcher->dispatch($event);
198197
$data = $event->getData();
199198

200-
if ($postMounts = $this->config[$component::class]['postMount'] ?? []) {
201-
foreach ($postMounts as $postMount) {
202-
if (null !== $newData = $component->$postMount($data)) {
203-
$data = $newData;
204-
}
199+
foreach ($componentMetadata->getPostMounts() as $postMount) {
200+
if (null !== $newData = $component->$postMount($data)) {
201+
$data = $newData;
205202
}
206203
}
207204

src/TwigComponent/src/ComponentMetadata.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,36 @@ public function getAttributesVar(): string
6767
return $this->get('attributes_var', 'attributes');
6868
}
6969

70+
/**
71+
* @return list<string>
72+
*
73+
* @internal
74+
*/
75+
public function getPreMounts(): array
76+
{
77+
return $this->get('pre_mount', []);
78+
}
79+
80+
/**
81+
* @return list<string>
82+
*
83+
* @internal
84+
*/
85+
public function getMounts(): array
86+
{
87+
return $this->get('mount', []);
88+
}
89+
90+
/**
91+
* @return list<string>
92+
*
93+
* @internal
94+
*/
95+
public function getPostMounts(): array
96+
{
97+
return $this->get('post_mount', []);
98+
}
99+
70100
public function get(string $key, mixed $default = null): mixed
71101
{
72102
return $this->config[$key] ?? $default;

src/TwigComponent/src/DependencyInjection/Compiler/TwigComponentPass.php

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,14 @@ private function calculateTemplate(string $componentName, ?array $defaults): str
111111

112112
return \sprintf('%s/%s.html.twig', rtrim($directory, '/'), str_replace(':', '/', $componentName));
113113
}
114-
114+
115115
/**
116116
* @param class-string $component
117117
* @return array{preMount: string[], mount: string[], postMount: string[]}
118118
*/
119119
private function getMountMethods(string $component): array
120120
{
121-
$preMount = [];
122-
$mount = [];
123-
$postMount = [];
124-
121+
$preMount = $mount = $postMount = [];
125122
foreach ((new \ReflectionClass($component))->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
126123
foreach ($method->getAttributes(PreMount::class) as $attribute) {
127124
$preMount[$method->getName()] = $attribute->newInstance()->priority;
@@ -133,24 +130,15 @@ private function getMountMethods(string $component): array
133130
$mount['mount'] = 0;
134131
}
135132
}
136-
137-
if ($preMount) {
138-
arsort($preMount);
139-
$preMount = array_keys($preMount);
140-
}
141-
if ($mount) {
142-
arsort($mount);
143-
$mount = array_keys($mount);
144-
}
145-
if ($postMount) {
146-
arsort($postMount);
147-
$postMount = array_keys($postMount);
148-
}
149-
133+
134+
arsort($preMount, SORT_NUMERIC);
135+
arsort($mount, SORT_NUMERIC);
136+
arsort($postMount, SORT_NUMERIC);
137+
150138
return [
151-
'preMount' => $preMount,
152-
'mount' => $mount,
153-
'postMount' => $postMount,
139+
'pre_mount' => array_keys($preMount),
140+
'mount' => array_keys($mount),
141+
'post_mount' => array_keys($postMount),
154142
];
155143
}
156144
}

src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeRootComponent.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@
77
#[AsTwigComponent]
88
class AcmeRootComponent
99
{
10-
1110
}

src/TwigComponent/tests/Fixtures/AcmeComponent/AcmeSubDir/AcmeOtherComponent.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@
77
#[AsTwigComponent]
88
class AcmeOtherComponent
99
{
10-
1110
}

src/TwigComponent/tests/Fixtures/Component/Conflict.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
class Conflict
99
{
1010
public string $name;
11-
}
11+
}

src/TwigComponent/tests/Fixtures/Component/SubDirectory/ComponentInSubDirectory.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@
77
#[AsTwigComponent]
88
class ComponentInSubDirectory
99
{
10-
1110
}

src/TwigComponent/tests/Integration/ComponentExtensionTest.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ public function testRenderingComponentWithNestedAttributes(): void
283283
{
284284
$output = $this->renderComponent('NestedAttributes');
285285

286-
$this->assertSame(<<<HTML
286+
$this->assertSame(
287+
<<<HTML
287288
<main>
288289
<div>
289290
<span>
@@ -302,7 +303,8 @@ public function testRenderingComponentWithNestedAttributes(): void
302303
'title:span:class' => 'baz',
303304
]);
304305

305-
$this->assertSame(<<<HTML
306+
$this->assertSame(
307+
<<<HTML
306308
<main class="foo">
307309
<div class="bar">
308310
<span class="baz">
@@ -324,7 +326,8 @@ public function testRenderingHtmlSyntaxComponentWithNestedAttributes(): void
324326
->render()
325327
;
326328

327-
$this->assertSame(<<<HTML
329+
$this->assertSame(
330+
<<<HTML
328331
<main>
329332
<div>
330333
<span>
@@ -343,7 +346,8 @@ public function testRenderingHtmlSyntaxComponentWithNestedAttributes(): void
343346
->render()
344347
;
345348

346-
$this->assertSame(<<<HTML
349+
$this->assertSame(
350+
<<<HTML
347351
<main class="foo" @class="vex">
348352
<div class="bar">
349353
<span class="baz">

src/TwigComponent/tests/Integration/ComponentFactoryTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public function testExceptionThrownIfRequiredMountParameterIsMissingFromPassedDa
9494

9595
public function testStringableObjectCanBePassedToComponent(): void
9696
{
97-
$attributes = $this->factory()->create('component_a', ['propB' => 'B', 'data-item-id-param' => new class {
97+
$attributes = $this->factory()->create('component_a', ['propB' => 'B', 'data-item-id-param' => new class () {
9898
public function __toString(): string
9999
{
100100
return 'test';

0 commit comments

Comments
 (0)