ControllerEvent.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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\Component\HttpKernel\Event;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\HttpKernelInterface;
  13. /**
  14. * Allows filtering of a controller callable.
  15. *
  16. * You can call getController() to retrieve the current controller. With
  17. * setController() you can set a new controller that is used in the processing
  18. * of the request.
  19. *
  20. * Controllers should be callables.
  21. *
  22. * @author Bernhard Schussek <bschussek@gmail.com>
  23. */
  24. final class ControllerEvent extends KernelEvent
  25. {
  26. private string|array|object $controller;
  27. private \ReflectionFunctionAbstract $controllerReflector;
  28. private array $attributes;
  29. public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType)
  30. {
  31. parent::__construct($kernel, $request, $requestType);
  32. $this->setController($controller);
  33. }
  34. public function getController(): callable
  35. {
  36. return $this->controller;
  37. }
  38. public function getControllerReflector(): \ReflectionFunctionAbstract
  39. {
  40. return $this->controllerReflector;
  41. }
  42. /**
  43. * @param array<class-string, list<object>>|null $attributes
  44. */
  45. public function setController(callable $controller, ?array $attributes = null): void
  46. {
  47. if (null !== $attributes) {
  48. $this->attributes = $attributes;
  49. }
  50. if (isset($this->controller) && ($controller instanceof \Closure ? $controller == $this->controller : $controller === $this->controller)) {
  51. $this->controller = $controller;
  52. return;
  53. }
  54. if (null === $attributes) {
  55. unset($this->attributes);
  56. }
  57. if (\is_array($controller) && method_exists(...$controller)) {
  58. $this->controllerReflector = new \ReflectionMethod(...$controller);
  59. } elseif (\is_string($controller) && str_contains($controller, '::')) {
  60. $this->controllerReflector = new \ReflectionMethod(...explode('::', $controller, 2));
  61. } else {
  62. $this->controllerReflector = new \ReflectionFunction($controller(...));
  63. }
  64. $this->controller = $controller;
  65. }
  66. /**
  67. * @template T of class-string|null
  68. *
  69. * @param T $className
  70. *
  71. * @return array<class-string, list<object>>|list<object>
  72. *
  73. * @psalm-return (T is null ? array<class-string, list<object>> : list<object>)
  74. */
  75. public function getAttributes(?string $className = null): array
  76. {
  77. if (isset($this->attributes)) {
  78. return null === $className ? $this->attributes : $this->attributes[$className] ?? [];
  79. }
  80. if (\is_array($this->controller) && method_exists(...$this->controller)) {
  81. $class = new \ReflectionClass($this->controller[0]);
  82. } elseif (\is_string($this->controller) && false !== $i = strpos($this->controller, '::')) {
  83. $class = new \ReflectionClass(substr($this->controller, 0, $i));
  84. } else {
  85. $class = str_contains($this->controllerReflector->name, '{closure') ? null : (\PHP_VERSION_ID >= 80111 ? $this->controllerReflector->getClosureCalledClass() : $this->controllerReflector->getClosureScopeClass());
  86. }
  87. $this->attributes = [];
  88. foreach (array_merge($class?->getAttributes() ?? [], $this->controllerReflector->getAttributes()) as $attribute) {
  89. if (class_exists($attribute->getName())) {
  90. $this->attributes[$attribute->getName()][] = $attribute->newInstance();
  91. }
  92. }
  93. return null === $className ? $this->attributes : $this->attributes[$className] ?? [];
  94. }
  95. }