vendor/symfony/ux-twig-component/src/Twig/ComponentExtension.php line 55

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\TwigComponent\Twig;
  11. use Psr\Container\ContainerInterface;
  12. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  13. use Symfony\UX\TwigComponent\ComponentRenderer;
  14. use Symfony\UX\TwigComponent\Event\PreRenderEvent;
  15. use Twig\Error\RuntimeError;
  16. use Twig\Extension\AbstractExtension;
  17. use Twig\TwigFunction;
  18. /**
  19. * @author Kevin Bond <kevinbond@gmail.com>
  20. *
  21. * @internal
  22. */
  23. final class ComponentExtension extends AbstractExtension implements ServiceSubscriberInterface
  24. {
  25. public function __construct(private ContainerInterface $container)
  26. {
  27. }
  28. public static function getSubscribedServices(): array
  29. {
  30. return [
  31. ComponentRenderer::class,
  32. ];
  33. }
  34. public function getFunctions(): array
  35. {
  36. return [
  37. new TwigFunction('component', [$this, 'render'], ['is_safe' => ['all']]),
  38. ];
  39. }
  40. public function getTokenParsers(): array
  41. {
  42. return [
  43. new ComponentTokenParser(),
  44. new PropsTokenParser(),
  45. ];
  46. }
  47. public function render(string $name, array $props = []): string
  48. {
  49. try {
  50. return $this->container->get(ComponentRenderer::class)->createAndRender($name, $props);
  51. } catch (\Throwable $e) {
  52. $this->throwRuntimeError($name, $e);
  53. }
  54. }
  55. public function extensionPreCreateForRender(string $name, array $props): ?string
  56. {
  57. try {
  58. return $this->container->get(ComponentRenderer::class)->preCreateForRender($name, $props);
  59. } catch (\Throwable $e) {
  60. $this->throwRuntimeError($name, $e);
  61. }
  62. }
  63. public function startEmbeddedComponentRender(string $name, array $props, array $context, string $hostTemplateName, int $index): PreRenderEvent
  64. {
  65. try {
  66. return $this->container->get(ComponentRenderer::class)->startEmbeddedComponentRender($name, $props, $context, $hostTemplateName, $index);
  67. } catch (\Throwable $e) {
  68. $this->throwRuntimeError($name, $e);
  69. }
  70. }
  71. public function finishEmbeddedComponentRender(): void
  72. {
  73. $this->container->get(ComponentRenderer::class)->finishEmbeddedComponentRender();
  74. }
  75. private function throwRuntimeError(string $name, \Throwable $e): void
  76. {
  77. // if it's already a Twig RuntimeError, just rethrow it
  78. if ($e instanceof RuntimeError) {
  79. throw $e;
  80. }
  81. if (!($e instanceof \Exception)) {
  82. $e = new \Exception($e->getMessage(), $e->getCode(), $e->getPrevious());
  83. }
  84. throw new RuntimeError(sprintf('Error rendering "%s" component: %s', $name, $e->getMessage()), previous: $e);
  85. }
  86. }