FrontController.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * Front controller responsible for dispatching application requests
  4. *
  5. * Copyright © Magento, Inc. All rights reserved.
  6. * See COPYING.txt for license details.
  7. */
  8. namespace Magento\Framework\App;
  9. use Magento\Framework\App\Request\InvalidRequestException;
  10. use Magento\Framework\Controller\ResultInterface;
  11. use Magento\Framework\App\Request\ValidatorInterface as RequestValidator;
  12. use Magento\Framework\Exception\NotFoundException;
  13. use Magento\Framework\Message\ManagerInterface as MessageManager;
  14. use Magento\Framework\App\Action\AbstractAction;
  15. use Psr\Log\LoggerInterface;
  16. use Magento\Framework\App\Request\Http as HttpRequest;
  17. /**
  18. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  19. */
  20. class FrontController implements FrontControllerInterface
  21. {
  22. /**
  23. * @var RouterListInterface
  24. */
  25. protected $_routerList;
  26. /**
  27. * @var ResponseInterface
  28. */
  29. protected $response;
  30. /**
  31. * @var RequestValidator
  32. */
  33. private $requestValidator;
  34. /**
  35. * @var MessageManager
  36. */
  37. private $messages;
  38. /**
  39. * @var LoggerInterface
  40. */
  41. private $logger;
  42. /**
  43. * @var bool
  44. */
  45. private $validatedRequest = false;
  46. /**
  47. * @param RouterListInterface $routerList
  48. * @param ResponseInterface $response
  49. * @param RequestValidator|null $requestValidator
  50. * @param MessageManager|null $messageManager
  51. * @param LoggerInterface|null $logger
  52. */
  53. public function __construct(
  54. RouterListInterface $routerList,
  55. ResponseInterface $response,
  56. ?RequestValidator $requestValidator = null,
  57. ?MessageManager $messageManager = null,
  58. ?LoggerInterface $logger = null
  59. ) {
  60. $this->_routerList = $routerList;
  61. $this->response = $response;
  62. $this->requestValidator = $requestValidator
  63. ?? ObjectManager::getInstance()->get(RequestValidator::class);
  64. $this->messages = $messageManager
  65. ?? ObjectManager::getInstance()->get(MessageManager::class);
  66. $this->logger = $logger
  67. ?? ObjectManager::getInstance()->get(LoggerInterface::class);
  68. }
  69. /**
  70. * Perform action and generate response
  71. *
  72. * @param RequestInterface|HttpRequest $request
  73. * @return ResponseInterface|ResultInterface
  74. * @throws \LogicException
  75. */
  76. public function dispatch(RequestInterface $request)
  77. {
  78. \Magento\Framework\Profiler::start('routers_match');
  79. $this->validatedRequest = false;
  80. $routingCycleCounter = 0;
  81. $result = null;
  82. while (!$request->isDispatched() && $routingCycleCounter++ < 100) {
  83. /** @var \Magento\Framework\App\RouterInterface $router */
  84. foreach ($this->_routerList as $router) {
  85. try {
  86. $actionInstance = $router->match($request);
  87. if ($actionInstance) {
  88. $result = $this->processRequest(
  89. $request,
  90. $actionInstance
  91. );
  92. break;
  93. }
  94. } catch (\Magento\Framework\Exception\NotFoundException $e) {
  95. $request->initForward();
  96. $request->setActionName('noroute');
  97. $request->setDispatched(false);
  98. break;
  99. }
  100. }
  101. }
  102. \Magento\Framework\Profiler::stop('routers_match');
  103. if ($routingCycleCounter > 100) {
  104. throw new \LogicException('Front controller reached 100 router match iterations');
  105. }
  106. return $result;
  107. }
  108. /**
  109. * @param HttpRequest $request
  110. * @param ActionInterface $actionInstance
  111. * @throws NotFoundException
  112. *
  113. * @return ResponseInterface|ResultInterface
  114. */
  115. private function processRequest(
  116. HttpRequest $request,
  117. ActionInterface $actionInstance
  118. ) {
  119. $request->setDispatched(true);
  120. $this->response->setNoCacheHeaders();
  121. $result = null;
  122. //Validating a request only once.
  123. if (!$this->validatedRequest) {
  124. try {
  125. $this->requestValidator->validate(
  126. $request,
  127. $actionInstance
  128. );
  129. } catch (InvalidRequestException $exception) {
  130. //Validation failed - processing validation results.
  131. $this->logger->debug(
  132. 'Request validation failed for action "'
  133. .get_class($actionInstance) .'"'
  134. );
  135. $result = $exception->getReplaceResult();
  136. if ($messages = $exception->getMessages()) {
  137. foreach ($messages as $message) {
  138. $this->messages->addErrorMessage($message);
  139. }
  140. }
  141. }
  142. $this->validatedRequest = true;
  143. }
  144. //Validation did not produce a result to replace the action's.
  145. if (!$result) {
  146. if ($actionInstance instanceof AbstractAction) {
  147. $result = $actionInstance->dispatch($request);
  148. } else {
  149. $result = $actionInstance->execute();
  150. }
  151. }
  152. //handling redirect to 404
  153. if ($result instanceof NotFoundException) {
  154. throw $result;
  155. }
  156. return $result;
  157. }
  158. }