/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/RouterListener.php

https://bitbucket.org/helfreire/tccwebservice · PHP · 140 lines · 83 code · 19 blank · 38 comment · 10 complexity · ccb62577373379af307166dcb7934334 MD5 · raw file

  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\EventListener;
  11. use Psr\Log\LoggerInterface;
  12. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
  15. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  16. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  17. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  18. use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
  19. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  20. use Symfony\Component\Routing\RequestContext;
  21. use Symfony\Component\Routing\RequestContextAwareInterface;
  22. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  23. use Symfony\Component\HttpFoundation\Request;
  24. /**
  25. * Initializes the context from the request and sets request attributes based on a matching route.
  26. *
  27. * @author Fabien Potencier <fabien@symfony.com>
  28. */
  29. class RouterListener implements EventSubscriberInterface
  30. {
  31. private $matcher;
  32. private $context;
  33. private $logger;
  34. private $request;
  35. /**
  36. * Constructor.
  37. *
  38. * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
  39. * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
  40. * @param LoggerInterface|null $logger The logger
  41. *
  42. * @throws \InvalidArgumentException
  43. */
  44. public function __construct($matcher, RequestContext $context = null, LoggerInterface $logger = null)
  45. {
  46. if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) {
  47. throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.');
  48. }
  49. if (null === $context && !$matcher instanceof RequestContextAwareInterface) {
  50. throw new \InvalidArgumentException('You must either pass a RequestContext or the matcher must implement RequestContextAwareInterface.');
  51. }
  52. $this->matcher = $matcher;
  53. $this->context = $context ?: $matcher->getContext();
  54. $this->logger = $logger;
  55. }
  56. /**
  57. * Sets the current Request.
  58. *
  59. * The application should call this method whenever the Request
  60. * object changes (entering a Request scope for instance, but
  61. * also when leaving a Request scope -- especially when they are
  62. * nested).
  63. *
  64. * @param Request|null $request A Request instance
  65. */
  66. public function setRequest(Request $request = null)
  67. {
  68. if (null !== $request && $this->request !== $request) {
  69. $this->context->fromRequest($request);
  70. }
  71. $this->request = $request;
  72. }
  73. public function onKernelRequest(GetResponseEvent $event)
  74. {
  75. $request = $event->getRequest();
  76. // initialize the context that is also used by the generator (assuming matcher and generator share the same context instance)
  77. // we call setRequest even if most of the time, it has already been done to keep compatibility
  78. // with frameworks which do not use the Symfony service container
  79. $this->setRequest($request);
  80. if ($request->attributes->has('_controller')) {
  81. // routing is already done
  82. return;
  83. }
  84. // add attributes based on the request (routing)
  85. try {
  86. // matching a request is more powerful than matching a URL path + context, so try that first
  87. if ($this->matcher instanceof RequestMatcherInterface) {
  88. $parameters = $this->matcher->matchRequest($request);
  89. } else {
  90. $parameters = $this->matcher->match($request->getPathInfo());
  91. }
  92. if (null !== $this->logger) {
  93. $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], $this->parametersToString($parameters)));
  94. }
  95. $request->attributes->add($parameters);
  96. unset($parameters['_route']);
  97. unset($parameters['_controller']);
  98. $request->attributes->set('_route_params', $parameters);
  99. } catch (ResourceNotFoundException $e) {
  100. $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
  101. throw new NotFoundHttpException($message, $e);
  102. } catch (MethodNotAllowedException $e) {
  103. $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods())));
  104. throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e);
  105. }
  106. }
  107. private function parametersToString(array $parameters)
  108. {
  109. $pieces = array();
  110. foreach ($parameters as $key => $val) {
  111. $pieces[] = sprintf('"%s": "%s"', $key, (is_string($val) ? $val : json_encode($val)));
  112. }
  113. return implode(', ', $pieces);
  114. }
  115. public static function getSubscribedEvents()
  116. {
  117. return array(
  118. KernelEvents::REQUEST => array(array('onKernelRequest', 32)),
  119. );
  120. }
  121. }