PageRenderTime 63ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/core/classes/request.php

https://bitbucket.org/arkross/venus
PHP | 601 lines | 260 code | 76 blank | 265 comment | 24 complexity | bed006fd4460692487af5c14ed07e992 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2011 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * @deprecated Replaced by HttpNotFoundException
  15. */
  16. class Request404Exception extends \FuelException
  17. {
  18. /**
  19. * When this type of exception isn't caught this method is called by
  20. * Error::exception_handler() to deal with the problem.
  21. */
  22. public function handle()
  23. {
  24. $response = new \Response(\View::forge('404'), 404);
  25. \Event::shutdown();
  26. $response->send(true);
  27. return;
  28. }
  29. }
  30. /**
  31. * The Request class is used to create and manage new and existing requests. There
  32. * is a main request which comes in from the browser or command line, then new
  33. * requests can be created for HMVC requests.
  34. *
  35. * Example Usage:
  36. *
  37. * $request = Request::forge('foo/bar')->execute();
  38. * echo $request->response();
  39. *
  40. * @package Fuel
  41. * @subpackage Core
  42. */
  43. class Request
  44. {
  45. /**
  46. * Holds the main request instance
  47. *
  48. * @var Request
  49. */
  50. protected static $main = false;
  51. /**
  52. * Holds the global active request instance
  53. *
  54. * @var Request
  55. */
  56. protected static $active = false;
  57. /**
  58. * This method is deprecated...use forge() instead.
  59. *
  60. * @deprecated until 1.2
  61. */
  62. public static function factory($uri = null, $route = true)
  63. {
  64. logger(\Fuel::L_WARNING, 'This method is deprecated. Please use a forge() instead.', __METHOD__);
  65. return static::forge($uri, $route);
  66. }
  67. /**
  68. * Generates a new request. The request is then set to be the active
  69. * request. If this is the first request, then save that as the main
  70. * request for the app.
  71. *
  72. * Usage:
  73. *
  74. * Request::forge('hello/world');
  75. *
  76. * @param string The URI of the request
  77. * @param mixed Internal: whether to use the routes; external: driver type or array with settings (driver key must be set)
  78. * @return Request The new request object
  79. */
  80. public static function forge($uri = null, $options = true)
  81. {
  82. is_bool($options) and $options = array('route' => $options);
  83. is_string($options) and $options = array('driver' => $options);
  84. if ( ! empty($options['driver']))
  85. {
  86. $class = \Inflector::words_to_upper('Request_'.$options['driver']);
  87. return $class::forge($uri, $options);
  88. }
  89. $request = new static($uri, isset($options['route']) ? $options['route'] : true);
  90. if (static::$active)
  91. {
  92. $request->parent = static::$active;
  93. static::$active->children[] = $request;
  94. }
  95. return $request;
  96. }
  97. /**
  98. * Returns the main request instance (the one from the browser or CLI).
  99. * This is the first executed Request, not necessarily the root parent of the current request.
  100. *
  101. * Usage:
  102. *
  103. * Request::main();
  104. *
  105. * @return Request
  106. */
  107. public static function main()
  108. {
  109. return static::$main;
  110. }
  111. /**
  112. * Returns the active request currently being used.
  113. *
  114. * Usage:
  115. *
  116. * Request::active();
  117. *
  118. * @param Request|null|false overwrite current request before returning, false prevents overwrite
  119. * @return Request
  120. */
  121. public static function active($request = false)
  122. {
  123. if ($request !== false)
  124. {
  125. static::$active = $request;
  126. }
  127. return static::$active;
  128. }
  129. /**
  130. * Returns the current request is an HMVC request
  131. *
  132. * Usage:
  133. *
  134. * if (Request::is_hmvc())
  135. * {
  136. * // Do something special...
  137. * return;
  138. * }
  139. *
  140. * @return bool
  141. */
  142. public static function is_hmvc()
  143. {
  144. return static::active() !== static::main();
  145. }
  146. /**
  147. * Shows a 404. Checks to see if a 404_override route is set, if not show
  148. * a default 404.
  149. *
  150. * @deprecated Remove in v1.2
  151. * @throws HttpNotFoundException
  152. */
  153. public static function show_404()
  154. {
  155. logger(\Fuel::L_WARNING, 'This method is deprecated. Please use a HttpNotFoundException instead.', __METHOD__);
  156. throw new \HttpNotFoundException();
  157. }
  158. /**
  159. * Reset's the active request with the previous one. This is needed after
  160. * the active request is finished.
  161. *
  162. * Usage:
  163. *
  164. * Request::reset_request();
  165. *
  166. * @return void
  167. */
  168. public static function reset_request()
  169. {
  170. // Let's make the previous Request active since we are done executing this one.
  171. static::$active = static::$active->parent();
  172. }
  173. /**
  174. * Holds the response object of the request.
  175. *
  176. * @var Response
  177. */
  178. public $response = null;
  179. /**
  180. * The Request's URI object.
  181. *
  182. * @var Uri
  183. */
  184. public $uri = null;
  185. /**
  186. * The request's route object
  187. *
  188. * @var Route
  189. */
  190. public $route = null;
  191. /**
  192. * The current module
  193. *
  194. * @var string
  195. */
  196. public $module = '';
  197. /**
  198. * The current controller directory
  199. *
  200. * @var string
  201. */
  202. public $directory = '';
  203. /**
  204. * The request's controller
  205. *
  206. * @var string
  207. */
  208. public $controller = '';
  209. /**
  210. * The request's controller action
  211. *
  212. * @var string
  213. */
  214. public $action = '';
  215. /**
  216. * The request's method params
  217. *
  218. * @var array
  219. */
  220. public $method_params = array();
  221. /**
  222. * The request's named params
  223. *
  224. * @var array
  225. */
  226. public $named_params = array();
  227. /**
  228. * Controller instance once instantiated
  229. *
  230. * @var Controller
  231. */
  232. public $controller_instance;
  233. /**
  234. * Search paths for the current active request
  235. *
  236. * @var array
  237. */
  238. public $paths = array();
  239. /**
  240. * Request that created this one
  241. *
  242. * @var Request
  243. */
  244. protected $parent = null;
  245. /**
  246. * Requests created by this request
  247. *
  248. * @var array
  249. */
  250. protected $children = array();
  251. /**
  252. * Creates the new Request object by getting a new URI object, then parsing
  253. * the uri with the Route class.
  254. *
  255. * Usage:
  256. *
  257. * $request = new Request('foo/bar');
  258. *
  259. * @param string the uri string
  260. * @param bool whether or not to route the URI
  261. * @return void
  262. */
  263. public function __construct($uri, $route = true)
  264. {
  265. $this->uri = new \Uri($uri);
  266. logger(\Fuel::L_INFO, 'Creating a new Request with URI = "'.$this->uri->uri.'"', __METHOD__);
  267. // check if a module was requested
  268. if (count($this->uri->segments) and $module_path = \Fuel::module_exists($this->uri->segments[0]))
  269. {
  270. // check if the module has routes
  271. if (is_file($module_path .= 'config/routes.php'))
  272. {
  273. $module = $this->uri->segments[0];
  274. // load and add the module routes
  275. $module_routes = \Fuel::load($module_path);
  276. $prepped_routes = array();
  277. foreach($module_routes as $name => $_route)
  278. {
  279. if ($name === '_root_')
  280. {
  281. $name = $module;
  282. }
  283. elseif (strpos($name, $module.'/') !== 0 and $name != $module and $name !== '_404_')
  284. {
  285. $name = $module.'/'.$name;
  286. }
  287. $prepped_routes[$name] = $_route;
  288. };
  289. // update the loaded list of routes
  290. \Router::add($prepped_routes, null, true);
  291. }
  292. }
  293. $this->route = \Router::process($this, $route);
  294. if ( ! $this->route)
  295. {
  296. return;
  297. }
  298. $this->module = $this->route->module;
  299. $this->controller = $this->route->controller;
  300. $this->action = $this->route->action;
  301. $this->method_params = $this->route->method_params;
  302. $this->named_params = $this->route->named_params;
  303. if ($this->route->module !== null)
  304. {
  305. $this->add_path(\Fuel::module_exists($this->module));
  306. }
  307. }
  308. /**
  309. * This executes the request and sets the output to be used later.
  310. *
  311. * Usage:
  312. *
  313. * $request = Request::forge('hello/world')->execute();
  314. *
  315. * @param array|null $method_params An array of parameters to pass to the method being executed
  316. * @return Request This request object
  317. */
  318. public function execute($method_params = null)
  319. {
  320. if (\Fuel::$profiling)
  321. {
  322. \Profiler::mark(__METHOD__.' Start');
  323. }
  324. logger(\Fuel::L_INFO, 'Called', __METHOD__);
  325. // Make the current request active
  326. static::$active = $this;
  327. // First request called is also the main request
  328. if ( ! static::$main)
  329. {
  330. logger(\Fuel::L_INFO, 'Setting main Request', __METHOD__);
  331. static::$main = $this;
  332. }
  333. if ( ! $this->route)
  334. {
  335. static::reset_request();
  336. throw new \HttpNotFoundException();
  337. }
  338. try
  339. {
  340. if ($this->route->callable !== null)
  341. {
  342. $response = call_user_func_array($this->route->callable, array($this));
  343. }
  344. else
  345. {
  346. $method_prefix = 'action_';
  347. $class = $this->controller;
  348. // Allow override of method params from execute
  349. if (is_array($method_params))
  350. {
  351. $this->method_params = array_merge($this->method_params, $method_params);
  352. }
  353. // If the class doesn't exist then 404
  354. if ( ! class_exists($class))
  355. {
  356. throw new \HttpNotFoundException();
  357. }
  358. // Load the controller using reflection
  359. $class = new \ReflectionClass($class);
  360. if ($class->isAbstract())
  361. {
  362. throw new \HttpNotFoundException();
  363. }
  364. // Create a new instance of the controller
  365. $this->controller_instance = $class->newInstance($this, new \Response);
  366. $this->action = $this->action ?: ($class->hasProperty('default_action') ? $class->getProperty('default_action')->getValue($this->controller_instance) : 'index');
  367. $method = $method_prefix.$this->action;
  368. // Allow to do in controller routing if method router(action, params) exists
  369. if ($class->hasMethod('router'))
  370. {
  371. $method = 'router';
  372. $this->method_params = array($this->action, $this->method_params);
  373. }
  374. if ($class->hasMethod($method))
  375. {
  376. $action = $class->getMethod($method);
  377. if ( ! $action->isPublic())
  378. {
  379. throw new \HttpNotFoundException();
  380. }
  381. $class->getMethod('before')->invoke($this->controller_instance);
  382. $response = $action->invokeArgs($this->controller_instance, $this->method_params);
  383. $response_after = $class->getMethod('after')->invoke($this->controller_instance, $response);
  384. // @TODO let the after method set the response directly
  385. if (is_null($response_after))
  386. {
  387. logger(\Fuel::L_WARNING, 'The '.$class->getName().'::after() method should accept and return the Controller\'s response, empty return for the after() method is deprecated.', __METHOD__);
  388. }
  389. else
  390. {
  391. $response = $response_after;
  392. }
  393. }
  394. else
  395. {
  396. throw new \HttpNotFoundException();
  397. }
  398. }
  399. }
  400. catch (\Exception $e)
  401. {
  402. static::reset_request();
  403. throw $e;
  404. }
  405. // Get the controller's output
  406. if (is_null($response))
  407. {
  408. // @TODO remove this in a future version as we will get rid of it.
  409. logger(\Fuel::L_WARNING, 'The '.$class->getName().' controller should return a string or a Response object, support for the $controller->response object is deprecated.', __METHOD__);
  410. $this->response = $this->controller_instance->response;
  411. }
  412. elseif ($response instanceof \Response)
  413. {
  414. $this->response = $response;
  415. }
  416. else
  417. {
  418. $this->response = \Response::forge($response, 200);
  419. }
  420. static::reset_request();
  421. if (\Fuel::$profiling)
  422. {
  423. \Profiler::mark(__METHOD__.' End');
  424. }
  425. return $this;
  426. }
  427. /**
  428. * Gets this Request's Response object;
  429. *
  430. * Usage:
  431. *
  432. * $response = Request::forge('foo/bar')->execute()->response();
  433. *
  434. * @return Response This Request's Response object
  435. */
  436. public function response()
  437. {
  438. return $this->response;
  439. }
  440. /**
  441. * Returns the Request that created this one
  442. *
  443. * @return Request|null
  444. */
  445. public function parent()
  446. {
  447. return $this->parent;
  448. }
  449. /**
  450. * Returns an array of Requests created by this one
  451. *
  452. * @return array
  453. */
  454. public function children()
  455. {
  456. return $this->children;
  457. }
  458. /**
  459. * Add to paths which are used by Fuel::find_file()
  460. *
  461. * @param string the new path
  462. * @param bool whether to add to the front or the back of the array
  463. * @return void
  464. */
  465. public function add_path($path, $prefix = false)
  466. {
  467. if ($prefix)
  468. {
  469. // prefix the path to the paths array
  470. array_unshift($this->paths, $path);
  471. }
  472. else
  473. {
  474. // add the new path
  475. $this->paths[] = $path;
  476. }
  477. }
  478. /**
  479. * Returns the array of currently loaded search paths.
  480. *
  481. * @return array the array of paths
  482. */
  483. public function get_paths()
  484. {
  485. return $this->paths;
  486. }
  487. /**
  488. * Gets a specific named parameter
  489. *
  490. * @param string $param Name of the parameter
  491. * @param mixed $default Default value
  492. * @return mixed
  493. */
  494. public function param($param, $default = null)
  495. {
  496. if ( ! isset($this->named_params[$param]))
  497. {
  498. return \Fuel::value($default);
  499. }
  500. return $this->named_params[$param];
  501. }
  502. /**
  503. * Gets all of the named parameters
  504. *
  505. * @return array
  506. */
  507. public function params()
  508. {
  509. return $this->named_params;
  510. }
  511. /**
  512. * PHP magic function returns the Output of the request.
  513. *
  514. * Usage:
  515. *
  516. * $request = Request::forge('hello/world')->execute();
  517. * echo $request;
  518. *
  519. * @return string the response
  520. */
  521. public function __toString()
  522. {
  523. return (string) $this->response;
  524. }
  525. }