HttpKernel.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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;
  11. use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
  12. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  13. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  14. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  15. use Symfony\Component\HttpKernel\Event\GetResponseEvent;
  16. use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
  17. use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpFoundation\Response;
  20. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  21. /**
  22. * HttpKernel notifies events to convert a Request object to a Response one.
  23. *
  24. * @author Fabien Potencier <fabien@symfony.com>
  25. */
  26. class HttpKernel implements HttpKernelInterface
  27. {
  28. private $dispatcher;
  29. private $resolver;
  30. /**
  31. * Constructor
  32. *
  33. * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
  34. * @param ControllerResolverInterface $resolver A ControllerResolverInterface instance
  35. */
  36. public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver)
  37. {
  38. $this->dispatcher = $dispatcher;
  39. $this->resolver = $resolver;
  40. }
  41. /**
  42. * Handles a Request to convert it to a Response.
  43. *
  44. * When $catch is true, the implementation must catch all exceptions
  45. * and do its best to convert them to a Response instance.
  46. *
  47. * @param Request $request A Request instance
  48. * @param integer $type The type of the request
  49. * (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST)
  50. * @param Boolean $catch Whether to catch exceptions or not
  51. *
  52. * @return Response A Response instance
  53. *
  54. * @throws \Exception When an Exception occurs during processing
  55. */
  56. public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
  57. {
  58. try {
  59. return $this->handleRaw($request, $type);
  60. } catch (\Exception $e) {
  61. if (false === $catch) {
  62. throw $e;
  63. }
  64. return $this->handleException($e, $request, $type);
  65. }
  66. }
  67. /**
  68. * Handles a request to convert it to a response.
  69. *
  70. * Exceptions are not caught.
  71. *
  72. * @param Request $request A Request instance
  73. * @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST)
  74. *
  75. * @return Response A Response instance
  76. *
  77. * @throws \LogicException If one of the listener does not behave as expected
  78. * @throws NotFoundHttpException When controller cannot be found
  79. */
  80. private function handleRaw(Request $request, $type = self::MASTER_REQUEST)
  81. {
  82. // request
  83. $event = new GetResponseEvent($this, $request, $type);
  84. $this->dispatcher->dispatch(Events::onCoreRequest, $event);
  85. if ($event->hasResponse()) {
  86. return $this->filterResponse($event->getResponse(), $request, $type);
  87. }
  88. // load controller
  89. if (false === $controller = $this->resolver->getController($request)) {
  90. throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". Maybe you forgot to add the matching route in your routing configuration?', $request->getPathInfo()));
  91. }
  92. $event = new FilterControllerEvent($this, $controller, $request, $type);
  93. $this->dispatcher->dispatch(Events::onCoreController, $event);
  94. $controller = $event->getController();
  95. // controller arguments
  96. $arguments = $this->resolver->getArguments($request, $controller);
  97. // call controller
  98. $response = call_user_func_array($controller, $arguments);
  99. // view
  100. if (!$response instanceof Response) {
  101. $event = new GetResponseForControllerResultEvent($this, $request, $type, $response);
  102. $this->dispatcher->dispatch(Events::onCoreView, $event);
  103. if ($event->hasResponse()) {
  104. $response = $event->getResponse();
  105. }
  106. if (!$response instanceof Response) {
  107. $msg = sprintf('The controller must return a response (%s given).', $this->varToString($response));
  108. // the user may have forgotten to return something
  109. if (null === $response) {
  110. $msg .= ' Did you forget to add a return statement somewhere in your controller?';
  111. }
  112. throw new \LogicException($msg);
  113. }
  114. }
  115. return $this->filterResponse($response, $request, $type);
  116. }
  117. /**
  118. * Filters a response object.
  119. *
  120. * @param Response $response A Response instance
  121. * @param string $message A error message in case the response is not a Response object
  122. * @param integer $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST)
  123. *
  124. * @return Response The filtered Response instance
  125. *
  126. * @throws \RuntimeException if the passed object is not a Response instance
  127. */
  128. private function filterResponse(Response $response, Request $request, $type)
  129. {
  130. $event = new FilterResponseEvent($this, $request, $type, $response);
  131. $this->dispatcher->dispatch(Events::onCoreResponse, $event);
  132. return $event->getResponse();
  133. }
  134. /**
  135. * Handles and exception by trying to convert it to a Response.
  136. *
  137. * @param \Exception $e An \Exception instance
  138. * @param Request $request A Request instance
  139. * @param integer $type The type of the request
  140. *
  141. * @return Response A Response instance
  142. */
  143. private function handleException(\Exception $e, $request, $type)
  144. {
  145. $event = new GetResponseForExceptionEvent($this, $request, $type, $e);
  146. $this->dispatcher->dispatch(Events::onCoreException, $event);
  147. if (!$event->hasResponse()) {
  148. throw $e;
  149. }
  150. return $this->filterResponse($event->getResponse(), $request, $type);
  151. }
  152. private function varToString($var)
  153. {
  154. if (is_object($var)) {
  155. return sprintf('[object](%s)', get_class($var));
  156. }
  157. if (is_array($var)) {
  158. $a = array();
  159. foreach ($var as $k => $v) {
  160. $a[] = sprintf('%s => %s', $k, $this->varToString($v));
  161. }
  162. return sprintf("[array](%s)", implode(', ', $a));
  163. }
  164. if (is_resource($var)) {
  165. return '[resource]';
  166. }
  167. if (null === $var) {
  168. return 'null';
  169. }
  170. return str_replace("\n", '', var_export((string) $var, true));
  171. }
  172. }