vendor/sensio/framework-extra-bundle/src/EventListener/ControllerListener.php line 44

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 Sensio\Bundle\FrameworkExtraBundle\EventListener;
  11. use Doctrine\Common\Annotations\Reader;
  12. use Doctrine\Persistence\Proxy;
  13. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. use Symfony\Component\HttpKernel\Event\KernelEvent;
  16. use Symfony\Component\HttpKernel\KernelEvents;
  17. /**
  18. * The ControllerListener class parses annotation blocks located in
  19. * controller classes.
  20. *
  21. * @author Fabien Potencier <fabien@symfony.com>
  22. */
  23. class ControllerListener implements EventSubscriberInterface
  24. {
  25. /**
  26. * @var Reader
  27. */
  28. private $reader;
  29. public function __construct(Reader $reader)
  30. {
  31. $this->reader = $reader;
  32. }
  33. /**
  34. * Modifies the Request object to apply configuration information found in
  35. * controllers annotations like the template to render or HTTP caching
  36. * configuration.
  37. */
  38. public function onKernelController(KernelEvent $event)
  39. {
  40. $controller = $event->getController();
  41. if (!\is_array($controller) && method_exists($controller, '__invoke')) {
  42. $controller = [$controller, '__invoke'];
  43. }
  44. if (!\is_array($controller)) {
  45. return;
  46. }
  47. $className = $this->getRealClass(\get_class($controller[0]));
  48. $object = new \ReflectionClass($className);
  49. $method = $object->getMethod($controller[1]);
  50. $classConfigurations = $this->getConfigurations($this->reader->getClassAnnotations($object));
  51. $methodConfigurations = $this->getConfigurations($this->reader->getMethodAnnotations($method));
  52. $configurations = [];
  53. foreach (array_merge(array_keys($classConfigurations), array_keys($methodConfigurations)) as $key) {
  54. if (!\array_key_exists($key, $classConfigurations)) {
  55. $configurations[$key] = $methodConfigurations[$key];
  56. } elseif (!\array_key_exists($key, $methodConfigurations)) {
  57. $configurations[$key] = $classConfigurations[$key];
  58. } else {
  59. if (\is_array($classConfigurations[$key])) {
  60. if (!\is_array($methodConfigurations[$key])) {
  61. throw new \UnexpectedValueException('Configurations should both be an array or both not be an array.');
  62. }
  63. $configurations[$key] = array_merge($classConfigurations[$key], $methodConfigurations[$key]);
  64. } else {
  65. // method configuration overrides class configuration
  66. $configurations[$key] = $methodConfigurations[$key];
  67. }
  68. }
  69. }
  70. $request = $event->getRequest();
  71. foreach ($configurations as $key => $attributes) {
  72. $request->attributes->set($key, $attributes);
  73. }
  74. }
  75. private function getConfigurations(array $annotations)
  76. {
  77. $configurations = [];
  78. foreach ($annotations as $configuration) {
  79. if ($configuration instanceof ConfigurationInterface) {
  80. if ($configuration->allowArray()) {
  81. $configurations['_'.$configuration->getAliasName()][] = $configuration;
  82. } elseif (!isset($configurations['_'.$configuration->getAliasName()])) {
  83. $configurations['_'.$configuration->getAliasName()] = $configuration;
  84. } else {
  85. throw new \LogicException(sprintf('Multiple "%s" annotations are not allowed.', $configuration->getAliasName()));
  86. }
  87. }
  88. }
  89. return $configurations;
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public static function getSubscribedEvents()
  95. {
  96. return [
  97. KernelEvents::CONTROLLER => 'onKernelController',
  98. ];
  99. }
  100. private static function getRealClass(string $class): string
  101. {
  102. if (class_exists(Proxy::class)) {
  103. if (false === $pos = strrpos($class, '\\'.Proxy::MARKER.'\\')) {
  104. return $class;
  105. }
  106. return substr($class, $pos + Proxy::MARKER_LENGTH + 2);
  107. }
  108. return $class;
  109. }
  110. }