Skip to content

Commit

Permalink
minor #2344 [TwigComponent] Improve ComponentFactory performances (sm…
Browse files Browse the repository at this point in the history
…nandre)

This PR was squashed before being merged into the 2.x branch.

Discussion
----------

[TwigComponent] Improve ComponentFactory performances

ComponentFactory Quick Optimization

Minor change with.. mid impact
(on large number of renders)

Commits
-------

6486933 [TwigComponent] Improve ComponentFactory performances
  • Loading branch information
smnandre committed Nov 10, 2024
2 parents 3a1ae4e + 6486933 commit 7dff0df
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 26 deletions.
62 changes: 37 additions & 25 deletions src/TwigComponent/src/ComponentFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Contracts\Service\ResetInterface;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
use Symfony\UX\TwigComponent\Event\PostMountEvent;
use Symfony\UX\TwigComponent\Event\PreMountEvent;
Expand All @@ -23,8 +24,12 @@
*
* @internal
*/
final class ComponentFactory
final class ComponentFactory implements ResetInterface
{
private static $mountMethods = [];
private static $preMountMethods = [];
private static $postMountMethods = [];

/**
* @param array<string, array> $config
* @param array<class-string, string> $classMap
Expand Down Expand Up @@ -141,37 +146,40 @@ public function get(string $name): object

private function mount(object $component, array &$data): void
{
try {
$method = (new \ReflectionClass($component))->getMethod('mount');
} catch (\ReflectionException) {
// no hydrate method
return;
}

if ($component instanceof AnonymousComponent) {
$component->mount($data);

return;
}

$parameters = [];
if (null === (self::$mountMethods[$component::class] ?? null)) {
try {
$mountMethod = self::$mountMethods[$component::class] = (new \ReflectionClass($component))->getMethod('mount');
} catch (\ReflectionException) {
self::$mountMethods[$component::class] = false;

foreach ($method->getParameters() as $refParameter) {
$name = $refParameter->getName();
return;
}
}

if (\array_key_exists($name, $data)) {
$parameters[] = $data[$name];
if (false === $mountMethod ??= self::$mountMethods[$component::class]) {
return;
}

$parameters = [];
foreach ($mountMethod->getParameters() as $refParameter) {
if (\array_key_exists($name = $refParameter->getName(), $data)) {
$parameters[] = $data[$name];
// remove the data element so it isn't used to set the property directly.
unset($data[$name]);
} elseif ($refParameter->isDefaultValueAvailable()) {
$parameters[] = $refParameter->getDefaultValue();
} else {
throw new \LogicException(\sprintf('%s::mount() has a required $%s parameter. Make sure this is passed or make give a default value.', $component::class, $refParameter->getName()));
throw new \LogicException(\sprintf('%s::mount() has a required $%s parameter. Make sure to pass it or give it a default value.', $component::class, $name));
}
}

$component->mount(...$parameters);
$mountMethod->invoke($component, ...$parameters);
}

private function preMount(object $component, array $data, ComponentMetadata $componentMetadata): array
Expand All @@ -180,10 +188,9 @@ private function preMount(object $component, array $data, ComponentMetadata $com
$this->eventDispatcher->dispatch($event);
$data = $event->getData();

foreach (AsTwigComponent::preMountMethods($component) as $method) {
$newData = $component->{$method->name}($data);

if (null !== $newData) {
$methods = self::$preMountMethods[$component::class] ??= AsTwigComponent::preMountMethods($component::class);
foreach ($methods as $method) {
if (null !== $newData = $method->invoke($component, $data)) {
$data = $newData;
}
}
Expand All @@ -199,19 +206,17 @@ private function postMount(object $component, array $data, ComponentMetadata $co
$event = new PostMountEvent($component, $data, $componentMetadata);
$this->eventDispatcher->dispatch($event);
$data = $event->getData();
$extraMetadata = $event->getExtraMetadata();

foreach (AsTwigComponent::postMountMethods($component) as $method) {
$newData = $component->{$method->name}($data);

if (null !== $newData) {
$methods = self::$postMountMethods[$component::class] ??= AsTwigComponent::postMountMethods($component::class);
foreach ($methods as $method) {
if (null !== $newData = $method->invoke($component, $data)) {
$data = $newData;
}
}

return [
'data' => $data,
'extraMetadata' => $extraMetadata,
'extraMetadata' => $event->getExtraMetadata(),
];
}

Expand Down Expand Up @@ -248,4 +253,11 @@ private function throwUnknownComponentException(string $name): void

throw new \InvalidArgumentException($message);
}

public function reset(): void
{
self::$mountMethods = [];
self::$preMountMethods = [];
self::$postMountMethods = [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ static function (ChildDefinition $definition, AsTwigComponent $attribute) {
new Reference('event_dispatcher'),
new AbstractArgument(\sprintf('Added in %s.', TwigComponentPass::class)),
])
->addTag('kernel.reset', ['method' => 'reset'])
;

$container->register('ux.twig_component.component_stack', ComponentStack::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function testMountCanHaveOptionalParameters(): void
public function testExceptionThrownIfRequiredMountParameterIsMissingFromPassedData(): void
{
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Symfony\UX\TwigComponent\Tests\Fixtures\Component\ComponentC::mount() has a required $propA parameter. Make sure this is passed or make give a default value.');
$this->expectExceptionMessage('Symfony\UX\TwigComponent\Tests\Fixtures\Component\ComponentC::mount() has a required $propA parameter. Make sure to pass it or give it a default value.');

$this->createComponent('component_c');
}
Expand Down

0 comments on commit 7dff0df

Please sign in to comment.