RoutingMiddleware.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.3.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Routing\Middleware;
  16. use Cake\Http\BaseApplication;
  17. use Cake\Http\MiddlewareQueue;
  18. use Cake\Http\Runner;
  19. use Cake\Routing\Exception\RedirectException;
  20. use Cake\Routing\Router;
  21. use Psr\Http\Message\ResponseInterface;
  22. use Psr\Http\Message\ServerRequestInterface;
  23. use Zend\Diactoros\Response\RedirectResponse;
  24. /**
  25. * Applies routing rules to the request and creates the controller
  26. * instance if possible.
  27. */
  28. class RoutingMiddleware
  29. {
  30. /**
  31. * The application that will have its routing hook invoked.
  32. *
  33. * @var \Cake\Http\BaseApplication
  34. */
  35. protected $app;
  36. /**
  37. * Constructor
  38. *
  39. * @param \Cake\Http\BaseApplication $app The application instance that routes are defined on.
  40. */
  41. public function __construct(BaseApplication $app = null)
  42. {
  43. $this->app = $app;
  44. }
  45. /**
  46. * Trigger the application's routes() hook if the application exists and Router isn't initialized.
  47. *
  48. * If the middleware is created without an Application, routes will be
  49. * loaded via the automatic route loading that pre-dates the routes() hook.
  50. *
  51. * @return void
  52. */
  53. protected function loadRoutes()
  54. {
  55. if ($this->app) {
  56. $builder = Router::createRouteBuilder('/');
  57. $this->app->routes($builder);
  58. }
  59. }
  60. /**
  61. * Apply routing and update the request.
  62. *
  63. * Any route/path specific middleware will be wrapped around $next and then the new middleware stack will be
  64. * invoked.
  65. *
  66. * @param \Psr\Http\Message\ServerRequestInterface $request The request.
  67. * @param \Psr\Http\Message\ResponseInterface $response The response.
  68. * @param callable $next The next middleware to call.
  69. * @return \Psr\Http\Message\ResponseInterface A response.
  70. */
  71. public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
  72. {
  73. $this->loadRoutes();
  74. try {
  75. Router::setRequestContext($request);
  76. $params = (array)$request->getAttribute('params', []);
  77. $middleware = [];
  78. if (empty($params['controller'])) {
  79. $parsedBody = $request->getParsedBody();
  80. if (is_array($parsedBody) && isset($parsedBody['_method'])) {
  81. $request = $request->withMethod($parsedBody['_method']);
  82. }
  83. $params = Router::parseRequest($request) + $params;
  84. if (isset($params['_middleware'])) {
  85. $middleware = $params['_middleware'];
  86. unset($params['_middleware']);
  87. }
  88. $request = $request->withAttribute('params', $params);
  89. }
  90. } catch (RedirectException $e) {
  91. return new RedirectResponse(
  92. $e->getMessage(),
  93. $e->getCode(),
  94. $response->getHeaders()
  95. );
  96. }
  97. $matching = Router::getRouteCollection()->getMiddleware($middleware);
  98. if (!$matching) {
  99. return $next($request, $response);
  100. }
  101. $matching[] = $next;
  102. $middleware = new MiddlewareQueue($matching);
  103. $runner = new Runner();
  104. return $runner->run($middleware, $request, $response);
  105. }
  106. }