Dispatcher.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 0.2.9
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Routing;
  16. use Cake\Controller\Controller;
  17. use Cake\Event\Event;
  18. use Cake\Event\EventListener;
  19. use Cake\Event\EventManagerTrait;
  20. use Cake\Network\Request;
  21. use Cake\Network\Response;
  22. use Cake\Routing\Exception\MissingControllerException;
  23. use LogicException;
  24. /**
  25. * Dispatcher converts Requests into controller actions. It uses the dispatched Request
  26. * to locate and load the correct controller. If found, the requested action is called on
  27. * the controller
  28. *
  29. */
  30. class Dispatcher {
  31. use EventManagerTrait;
  32. /**
  33. * Connected filter objects
  34. *
  35. * @var array
  36. */
  37. protected $_filters = [];
  38. /**
  39. * Dispatches and invokes given Request, handing over control to the involved controller. If the controller is set
  40. * to autoRender, via Controller::$autoRender, then Dispatcher will render the view.
  41. *
  42. * Actions in CakePHP can be any public method on a controller, that is not declared in Controller. If you
  43. * want controller methods to be public and in-accessible by URL, then prefix them with a `_`.
  44. * For example `public function _loadPosts() { }` would not be accessible via URL. Private and protected methods
  45. * are also not accessible via URL.
  46. *
  47. * If no controller of given name can be found, invoke() will throw an exception.
  48. * If the controller is found, and the action is not found an exception will be thrown.
  49. *
  50. * @param \Cake\Network\Request $request Request object to dispatch.
  51. * @param \Cake\Network\Response $response Response object to put the results of the dispatch into.
  52. * @return string|void if `$request['return']` is set then it returns response body, null otherwise
  53. * @throws \Cake\Routing\Exception\MissingControllerException When the controller is missing.
  54. */
  55. public function dispatch(Request $request, Response $response) {
  56. $beforeEvent = $this->dispatchEvent('Dispatcher.beforeDispatch', compact('request', 'response'));
  57. $request = $beforeEvent->data['request'];
  58. if ($beforeEvent->result instanceof Response) {
  59. if (isset($request->params['return'])) {
  60. return $beforeEvent->result->body();
  61. }
  62. $beforeEvent->result->send();
  63. return;
  64. }
  65. $controller = false;
  66. if (isset($beforeEvent->data['controller'])) {
  67. $controller = $beforeEvent->data['controller'];
  68. }
  69. if (!($controller instanceof Controller)) {
  70. throw new MissingControllerException(array(
  71. 'class' => $request->params['controller'],
  72. 'plugin' => empty($request->params['plugin']) ? null : $request->params['plugin'],
  73. 'prefix' => empty($request->params['prefix']) ? null : $request->params['prefix'],
  74. '_ext' => empty($request->params['_ext']) ? null : $request->params['_ext']
  75. ));
  76. }
  77. $response = $this->_invoke($controller);
  78. if (isset($request->params['return'])) {
  79. return $response->body();
  80. }
  81. $afterEvent = $this->dispatchEvent('Dispatcher.afterDispatch', compact('request', 'response'));
  82. $afterEvent->data['response']->send();
  83. }
  84. /**
  85. * Initializes the components and models a controller will be using.
  86. * Triggers the controller action and invokes the rendering if Controller::$autoRender
  87. * is true. If a response object is returned by controller action that is returned
  88. * else controller's $response property is returned.
  89. *
  90. * @param Controller $controller Controller to invoke
  91. * @return \Cake\Network\Response The resulting response object
  92. * @throws \LogicException If data returned by controller action is not an
  93. * instance of Response
  94. */
  95. protected function _invoke(Controller $controller) {
  96. $result = $controller->startupProcess();
  97. if ($result instanceof Response) {
  98. return $result;
  99. }
  100. $response = $controller->invokeAction();
  101. if ($response !== null && !($response instanceof Response)) {
  102. throw new LogicException('Controller action can only return an instance of Response');
  103. }
  104. if (!$response && $controller->autoRender) {
  105. $response = $controller->render();
  106. } elseif (!$response) {
  107. $response = $controller->response;
  108. }
  109. $result = $controller->shutdownProcess();
  110. if ($result instanceof Response) {
  111. return $result;
  112. }
  113. return $response;
  114. }
  115. /**
  116. * Add a filter to this dispatcher.
  117. *
  118. * The added filter will be attached to the event manager used
  119. * by this dispatcher.
  120. *
  121. * @param \Cake\Event\EventListener $filter The filter to connect. Can be
  122. * any EventListener. Typically an instance of \Cake\Routing\DispatcherFilter.
  123. * @return void
  124. */
  125. public function addFilter(EventListener $filter) {
  126. $this->_filters[] = $filter;
  127. $this->eventManager()->attach($filter);
  128. }
  129. /**
  130. * Get the list of connected filters.
  131. *
  132. * @return array
  133. */
  134. public function filters() {
  135. return $this->_filters;
  136. }
  137. }