controller.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <?php namespace Laravel\Routing;
  2. use Laravel\IoC;
  3. use Laravel\View;
  4. use Laravel\Request;
  5. use Laravel\Redirect;
  6. use Laravel\Response;
  7. abstract class Controller {
  8. /**
  9. * The layout being used by the controller.
  10. *
  11. * @var string
  12. */
  13. public $layout;
  14. /**
  15. * Indicates if the controller uses RESTful routing.
  16. *
  17. * @var bool
  18. */
  19. public $restful = false;
  20. /**
  21. * The filters assigned to the controller.
  22. *
  23. * @var array
  24. */
  25. protected $filters = array();
  26. /**
  27. * Handle the delegation of a route to a controller method.
  28. *
  29. * The controller destination should follow a {controller}@{method} convention.
  30. * Nested controllers may be delegated to using dot syntax.
  31. *
  32. * For example, a destination of "user.profile@show" would call the User_Profile
  33. * controller's show method with the given parameters.
  34. *
  35. * @param string $destination
  36. * @param array $parameters
  37. * @return Response
  38. */
  39. public static function call($destination, $parameters = array())
  40. {
  41. if (strpos($destination, '@') === false)
  42. {
  43. throw new \InvalidArgumentException("Route delegate [{$destination}] has an invalid format.");
  44. }
  45. list($controller, $method) = explode('@', $destination);
  46. $controller = static::resolve($controller);
  47. if (is_null($controller))
  48. {
  49. return Response::error('404');
  50. }
  51. return $controller->execute($method, $parameters);
  52. }
  53. /**
  54. * Resolve a controller name to a controller instance.
  55. *
  56. * @param string $container
  57. * @param string $controller
  58. * @return Controller
  59. */
  60. public static function resolve($controller)
  61. {
  62. if ( ! static::load($controller)) return;
  63. // If the controller is registered in the IoC container, we will resolve
  64. // it out of the container. Using constructor injection on controllers
  65. // via the container allows more flexible and testable applications.
  66. if (IoC::registered('controllers.'.$controller))
  67. {
  68. return IoC::resolve('controllers.'.$controller);
  69. }
  70. $controller = str_replace(' ', '_', ucwords(str_replace('.', ' ', $controller))).'_Controller';
  71. $controller = new $controller;
  72. // If the controller has specified a layout to be used when rendering
  73. // views, we will instantiate the layout instance and set it to the
  74. // layout property, replacing the string layout name.
  75. if ( ! is_null($controller->layout))
  76. {
  77. $controller->layout = View::make($controller->layout);
  78. }
  79. return $controller;
  80. }
  81. /**
  82. * Load the file for a given controller.
  83. *
  84. * @param string $controller
  85. * @return bool
  86. */
  87. protected static function load($controller)
  88. {
  89. $controller = strtolower(str_replace('.', '/', $controller));
  90. if (file_exists($path = CONTROLLER_PATH.$controller.EXT))
  91. {
  92. require_once $path;
  93. return true;
  94. }
  95. return false;
  96. }
  97. /**
  98. * Execute a controller method with the given parameters.
  99. *
  100. * @param string $method
  101. * @param array $parameters
  102. * @return Response
  103. */
  104. public function execute($method, $parameters = array())
  105. {
  106. // Again, as was the case with route closures, if the controller
  107. // "before" filters return a response, it will be considered the
  108. // response to the request and the controller method will not be
  109. // used to handle the request to the application.
  110. $response = Filter::run($this->filters('before', $method), array(), true);
  111. if (is_null($response))
  112. {
  113. // The developer may mark the controller as being "RESTful" which
  114. // indicates that the controller actions are prefixed with the
  115. // HTTP verb they respond to rather than the word "action".
  116. if ($this->restful)
  117. {
  118. $action = strtolower(Request::method()).'_'.$method;
  119. }
  120. else
  121. {
  122. $action = "action_{$method}";
  123. }
  124. $response = call_user_func_array(array($this, $action), $parameters);
  125. // If the controller has specified a layout view. The response
  126. // returned by the controller method will be bound to that view
  127. // and the layout will be considered the response.
  128. if (is_null($response) and ! is_null($this->layout))
  129. {
  130. $response = $this->layout;
  131. }
  132. }
  133. if ( ! $response instanceof Response)
  134. {
  135. $response = new Response($response);
  136. }
  137. // Stringify the response. We need to force the response to be
  138. // stringed before closing the session, since the developer may
  139. // be using the session within their views, so we cannot age
  140. // the session data until the view is rendered.
  141. $response->content = $response->render();
  142. Filter::run($this->filters('after', $method), array($response));
  143. return $response;
  144. }
  145. /**
  146. * Register filters on the controller's methods.
  147. *
  148. * Generally, this method will be used in the controller's constructor.
  149. *
  150. * <code>
  151. * // Set a "foo" after filter on the controller
  152. * $this->filter('before', 'foo');
  153. *
  154. * // Set several filters on an explicit group of methods
  155. * $this->filter('after', 'foo|bar')->only(array('user', 'profile'));
  156. * </code>
  157. *
  158. * @param string|array $filters
  159. * @return Filter_Collection
  160. */
  161. protected function filter($name, $filters)
  162. {
  163. $this->filters[$name][] = new Filter_Collection($name, $filters);
  164. return $this->filters[$name][count($this->filters[$name]) - 1];
  165. }
  166. /**
  167. * Get an array of filter names defined for the destination.
  168. *
  169. * @param string $name
  170. * @param string $method
  171. * @return array
  172. */
  173. protected function filters($name, $method)
  174. {
  175. if ( ! isset($this->filters[$name])) return array();
  176. $filters = array();
  177. foreach ($this->filters[$name] as $filter)
  178. {
  179. if ($filter->applies($method))
  180. {
  181. $filters = array_merge($filters, $filter->filters);
  182. }
  183. }
  184. return array_unique($filters);
  185. }
  186. /**
  187. * Magic Method to handle calls to undefined functions on the controller.
  188. *
  189. * By default, the 404 response will be returned for an calls to undefined
  190. * methods on the controller. However, this method may also be overridden
  191. * and used as a pseudo-router by the controller.
  192. */
  193. public function __call($method, $parameters)
  194. {
  195. return Response::error('404');
  196. }
  197. /**
  198. * Dynamically resolve items from the application IoC container.
  199. *
  200. * <code>
  201. * // Retrieve an object registered in the container as "mailer"
  202. * $mailer = $this->mailer;
  203. *
  204. * // Equivalent call using the IoC container instance
  205. * $mailer = IoC::resolve('mailer');
  206. * </code>
  207. */
  208. public function __get($key)
  209. {
  210. if (IoC::registered($key))
  211. {
  212. return IoC::resolve($key);
  213. }
  214. throw new \OutOfBoundsException("Attempting to access undefined property [$key] on controller.");
  215. }
  216. }