vendor/symfony/ux-live-component/src/EventListener/InterceptChildComponentRenderSubscriber.php line 42

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\UX\LiveComponent\EventListener;
  11. use Psr\Container\ContainerInterface;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  14. use Symfony\UX\LiveComponent\Twig\DeterministicTwigIdCalculator;
  15. use Symfony\UX\LiveComponent\Util\ChildComponentPartialRenderer;
  16. use Symfony\UX\LiveComponent\Util\LiveControllerAttributesCreator;
  17. use Symfony\UX\TwigComponent\ComponentStack;
  18. use Symfony\UX\TwigComponent\Event\PreCreateForRenderEvent;
  19. /**
  20.  * Responsible for rendering children as empty elements during a re-render.
  21.  *
  22.  * @author Ryan Weaver <ryan@symfonycasts.com>
  23.  *
  24.  * @experimental
  25.  *
  26.  * @internal
  27.  */
  28. class InterceptChildComponentRenderSubscriber implements EventSubscriberInterfaceServiceSubscriberInterface
  29. {
  30.     public const CHILDREN_FINGERPRINTS_METADATA_KEY 'children_fingerprints';
  31.     public function __construct(
  32.         private ComponentStack $componentStack,
  33.         private ContainerInterface $container,
  34.     ) {
  35.     }
  36.     public function preComponentCreated(PreCreateForRenderEvent $event): void
  37.     {
  38.         // if there is already a component, that's a parent. Else, this is not a child.
  39.         if (null === $parentComponent $this->componentStack->getCurrentComponent()) {
  40.             return;
  41.         }
  42.         if (!$parentComponent->hasExtraMetadata(self::CHILDREN_FINGERPRINTS_METADATA_KEY)) {
  43.             return;
  44.         }
  45.         $childFingerprints $parentComponent->getExtraMetadata(self::CHILDREN_FINGERPRINTS_METADATA_KEY);
  46.         // get the deterministic id for this child, but without incrementing the counter yet
  47.         if (isset($event->getInputProps()['data-live-id'])) {
  48.             $deterministicId $event->getInputProps()['data-live-id'];
  49.         } else {
  50.             $key $event->getInputProps()[LiveControllerAttributesCreator::KEY_PROP_NAME] ?? null;
  51.             $deterministicId $this->getDeterministicIdCalculator()->calculateDeterministicId(incrementfalsekey$key);
  52.         }
  53.         if (!isset($childFingerprints[$deterministicId])) {
  54.             // child fingerprint wasn't set, it is likely a new child, allow it to render fully
  55.             return;
  56.         }
  57.         // increment the internal counter now to keep "counter" consistency if we're
  58.         // in a loop of children being rendered on the same line
  59.         // we need to do this because this component will *not* ever hit
  60.         // AddLiveAttributesSubscriber where the counter is normally incremented
  61.         $this->getDeterministicIdCalculator()->calculateDeterministicId(incrementtrue);
  62.         $childPartialRenderer $this->container->get(ChildComponentPartialRenderer::class);
  63.         \assert($childPartialRenderer instanceof ChildComponentPartialRenderer);
  64.         $rendered $childPartialRenderer->renderChildComponent(
  65.             $deterministicId,
  66.             $childFingerprints[$deterministicId]['fingerprint'],
  67.             $childFingerprints[$deterministicId]['tag'],
  68.             $event->getName(),
  69.             $event->getInputProps(),
  70.         );
  71.         $event->setRenderedString($rendered);
  72.     }
  73.     public static function getSubscribedServices(): array
  74.     {
  75.         return [
  76.             DeterministicTwigIdCalculator::class,
  77.             ChildComponentPartialRenderer::class,
  78.         ];
  79.     }
  80.     public static function getSubscribedEvents(): array
  81.     {
  82.         return [
  83.             PreCreateForRenderEvent::class => 'preComponentCreated',
  84.         ];
  85.     }
  86.     private function getDeterministicIdCalculator(): DeterministicTwigIdCalculator
  87.     {
  88.         return $this->container->get(DeterministicTwigIdCalculator::class);
  89.     }
  90.     private function getAttributesCreator(): LiveControllerAttributesCreator
  91.     {
  92.         return $this->container->get(LiveControllerAttributesCreator::class);
  93.     }
  94. }