vendor/symfony/ux-live-component/src/Attribute/AsLiveComponent.php line 43

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\Attribute;
  11. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  12. use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
  13. /**
  14. * An attribute to register a LiveComponent.
  15. *
  16. * @see https://symfony.com/bundles/ux-live-component
  17. *
  18. * @author Kevin Bond <kevinbond@gmail.com>
  19. */
  20. #[\Attribute(\Attribute::TARGET_CLASS)]
  21. final class AsLiveComponent extends AsTwigComponent
  22. {
  23. public string $route;
  24. public string $method;
  25. public int $urlReferenceType;
  26. private ?string $defaultAction;
  27. /**
  28. * @param string|null $name The component name (ie: TodoList)
  29. * @param string|null $template The template path of the component (ie: components/TodoList.html.twig).
  30. * @param string|null $defaultAction The default action to call when the component is mounted (ie: __invoke)
  31. * @param bool $exposePublicProps Whether to expose every public property as a Twig variable
  32. * @param string $attributesVar The name of the special "attributes" variable in the template
  33. * @param string $route The route used to render the component & handle actions
  34. * @param string $method The HTTP method to use
  35. * @param UrlGeneratorInterface::* $urlReferenceType Which type of URL should be generated for the given route
  36. */
  37. public function __construct(
  38. ?string $name = null,
  39. ?string $template = null,
  40. ?string $defaultAction = null,
  41. bool $exposePublicProps = true,
  42. string $attributesVar = 'attributes',
  43. string|bool $route = 'ux_live_component',
  44. string $method = 'post',
  45. int|string $urlReferenceType = UrlGeneratorInterface::ABSOLUTE_PATH,
  46. public bool|int $csrf = true, // @deprecated
  47. ) {
  48. if (8 < \func_num_args() || \is_bool($route)) {
  49. trigger_deprecation('symfony/ux-live-component', '2.21', 'Argument "$csrf" of "#[%s]" has no effect anymore and is deprecated.', static::class);
  50. }
  51. if (\is_bool($route)) {
  52. $this->csrf = $route;
  53. $route = $method;
  54. $method = $urlReferenceType;
  55. $urlReferenceType = $csrf;
  56. switch (\func_num_args()) {
  57. case 6: $route = 'ux_live_component';
  58. // no break
  59. case 7: $method = 'post';
  60. // no break
  61. case 8: $urlReferenceType = UrlGeneratorInterface::ABSOLUTE_PATH;
  62. // no break
  63. default:
  64. }
  65. }
  66. parent::__construct($name, $template, $exposePublicProps, $attributesVar);
  67. $this->defaultAction = $defaultAction;
  68. $this->route = $route;
  69. $this->method = strtolower($method);
  70. $this->urlReferenceType = $urlReferenceType;
  71. if (!\in_array($method, ['get', 'post'])) {
  72. throw new \UnexpectedValueException('$method must be either \'get\' or \'post\'.');
  73. }
  74. }
  75. /**
  76. * @internal
  77. */
  78. public function serviceConfig(): array
  79. {
  80. return array_merge(parent::serviceConfig(), [
  81. 'default_action' => $this->defaultAction,
  82. 'live' => true,
  83. 'csrf' => $this->csrf,
  84. 'route' => $this->route,
  85. 'method' => $this->method,
  86. 'url_reference_type' => $this->urlReferenceType,
  87. ]);
  88. }
  89. /**
  90. * @internal
  91. *
  92. * @param object|class-string $component
  93. */
  94. public static function isActionAllowed(object|string $component, string $action): bool
  95. {
  96. foreach (self::attributeMethodsFor(LiveAction::class, $component) as $method) {
  97. if ($action === $method->getName()) {
  98. return true;
  99. }
  100. }
  101. return false;
  102. }
  103. /**
  104. * @internal
  105. *
  106. * @param object|class-string $component
  107. *
  108. * @return \ReflectionMethod[]
  109. */
  110. public static function preReRenderMethods(object|string $component): iterable
  111. {
  112. return self::attributeMethodsByPriorityFor($component, PreReRender::class);
  113. }
  114. /**
  115. * @internal
  116. *
  117. * @param object|class-string $component
  118. *
  119. * @return \ReflectionMethod[]
  120. */
  121. public static function postHydrateMethods(object|string $component): iterable
  122. {
  123. return self::attributeMethodsByPriorityFor($component, PostHydrate::class);
  124. }
  125. /**
  126. * @internal
  127. *
  128. * @param object|class-string $component
  129. *
  130. * @return \ReflectionMethod[]
  131. */
  132. public static function preDehydrateMethods(object|string $component): iterable
  133. {
  134. return self::attributeMethodsByPriorityFor($component, PreDehydrate::class);
  135. }
  136. /**
  137. * @internal
  138. *
  139. * @param object|class-string $component
  140. *
  141. * @return array<array{action: string, event: string}>
  142. */
  143. public static function liveListeners(object|string $component): array
  144. {
  145. $listeners = [];
  146. foreach (self::attributeMethodsFor(LiveListener::class, $component) as $method) {
  147. foreach ($method->getAttributes(LiveListener::class) as $attribute) {
  148. $listeners[] = ['action' => $method->getName(), 'event' => $attribute->newInstance()->getEventName()];
  149. }
  150. }
  151. return $listeners;
  152. }
  153. }