PageRenderTime 547ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/applications/core/lib/Zend/Controller/Router/Rewrite.php

#
PHP | 455 lines | 214 code | 62 blank | 179 comment | 38 complexity | ec48dfa44221642772d5b3b51ba0857d MD5 | raw file
Possible License(s): CC0-1.0
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @package Zend_Controller
  16. * @subpackage Router
  17. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @version $Id: Rewrite.php 14248 2009-03-08 18:51:35Z dasprid $
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /** Zend_Loader */
  22. require_once 'Zend/Loader.php';
  23. /** Zend_Controller_Router_Abstract */
  24. require_once 'Zend/Controller/Router/Abstract.php';
  25. /** Zend_Controller_Router_Route */
  26. require_once 'Zend/Controller/Router/Route.php';
  27. /**
  28. * Ruby routing based Router.
  29. *
  30. * @package Zend_Controller
  31. * @subpackage Router
  32. * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
  33. * @license http://framework.zend.com/license/new-bsd New BSD License
  34. * @see http://manuals.rubyonrails.com/read/chapter/65
  35. */
  36. class Zend_Controller_Router_Rewrite extends Zend_Controller_Router_Abstract
  37. {
  38. /**
  39. * Whether or not to use default routes
  40. *
  41. * @var boolean
  42. */
  43. protected $_useDefaultRoutes = true;
  44. /**
  45. * Array of routes to match against
  46. *
  47. * @var array
  48. */
  49. protected $_routes = array();
  50. /**
  51. * Currently matched route
  52. *
  53. * @var Zend_Controller_Router_Route_Interface
  54. */
  55. protected $_currentRoute = null;
  56. /**
  57. * Global parameters given to all routes
  58. *
  59. * @var array
  60. */
  61. protected $_globalParams = array();
  62. /**
  63. * Add default routes which are used to mimic basic router behaviour
  64. *
  65. * @return Zend_Controller_Router_Rewrite
  66. */
  67. public function addDefaultRoutes()
  68. {
  69. if (!$this->hasRoute('default')) {
  70. $dispatcher = $this->getFrontController()->getDispatcher();
  71. $request = $this->getFrontController()->getRequest();
  72. require_once 'Zend/Controller/Router/Route/Module.php';
  73. $compat = new Zend_Controller_Router_Route_Module(array(), $dispatcher, $request);
  74. $this->_routes = array_merge(array('default' => $compat), $this->_routes);
  75. }
  76. return $this;
  77. }
  78. /**
  79. * Add route to the route chain
  80. *
  81. * If route contains method setRequest(), it is initialized with a request object
  82. *
  83. * @param string $name Name of the route
  84. * @param Zend_Controller_Router_Route_Interface $route Instance of the route
  85. * @return Zend_Controller_Router_Rewrite
  86. */
  87. public function addRoute($name, Zend_Controller_Router_Route_Interface $route)
  88. {
  89. if (method_exists($route, 'setRequest')) {
  90. $route->setRequest($this->getFrontController()->getRequest());
  91. }
  92. $this->_routes[$name] = $route;
  93. return $this;
  94. }
  95. /**
  96. * Add routes to the route chain
  97. *
  98. * @param array $routes Array of routes with names as keys and routes as values
  99. * @return Zend_Controller_Router_Rewrite
  100. */
  101. public function addRoutes($routes) {
  102. foreach ($routes as $name => $route) {
  103. $this->addRoute($name, $route);
  104. }
  105. return $this;
  106. }
  107. /**
  108. * Create routes out of Zend_Config configuration
  109. *
  110. * Example INI:
  111. * routes.archive.route = "archive/:year/*"
  112. * routes.archive.defaults.controller = archive
  113. * routes.archive.defaults.action = show
  114. * routes.archive.defaults.year = 2000
  115. * routes.archive.reqs.year = "\d+"
  116. *
  117. * routes.news.type = "Zend_Controller_Router_Route_Static"
  118. * routes.news.route = "news"
  119. * routes.news.defaults.controller = "news"
  120. * routes.news.defaults.action = "list"
  121. *
  122. * And finally after you have created a Zend_Config with above ini:
  123. * $router = new Zend_Controller_Router_Rewrite();
  124. * $router->addConfig($config, 'routes');
  125. *
  126. * @param Zend_Config $config Configuration object
  127. * @param string $section Name of the config section containing route's definitions
  128. * @throws Zend_Controller_Router_Exception
  129. * @return Zend_Controller_Router_Rewrite
  130. */
  131. public function addConfig(Zend_Config $config, $section = null)
  132. {
  133. if ($section !== null) {
  134. if ($config->{$section} === null) {
  135. require_once 'Zend/Controller/Router/Exception.php';
  136. throw new Zend_Controller_Router_Exception("No route configuration in section '{$section}'");
  137. }
  138. $config = $config->{$section};
  139. }
  140. foreach ($config as $name => $info) {
  141. $route = $this->_getRouteFromConfig($info);
  142. if ($route instanceof Zend_Controller_Router_Route_Chain) {
  143. if (!isset($info->chain)) {
  144. require_once 'Zend/Controller/Router/Exception.php';
  145. throw new Zend_Controller_Router_Exception("No chain defined");
  146. }
  147. if ($info->chain instanceof Zend_Config) {
  148. $childRouteNames = $info->chain;
  149. } else {
  150. $childRouteNames = explode(',', $info->chain);
  151. }
  152. foreach ($childRouteNames as $childRouteName) {
  153. $childRoute = $this->getRoute(trim($childRouteName));
  154. $route->chain($childRoute);
  155. }
  156. $this->addRoute($name, $route);
  157. } elseif (isset($info->chains) && $info->chains instanceof Zend_Config) {
  158. $this->_addChainRoutesFromConfig($name, $route, $info->chains);
  159. } else {
  160. $this->addRoute($name, $route);
  161. }
  162. }
  163. return $this;
  164. }
  165. /**
  166. * Get a route frm a config instance
  167. *
  168. * @param Zend_Config $info
  169. * @return Zend_Controller_Router_Route_Interface
  170. */
  171. protected function _getRouteFromConfig(Zend_Config $info)
  172. {
  173. $class = (isset($info->type)) ? $info->type : 'Zend_Controller_Router_Route';
  174. Zend_Loader::loadClass($class);
  175. $route = call_user_func(array($class, 'getInstance'), $info);
  176. if (isset($info->abstract) && $info->abstract && method_exists($route, 'isAbstract')) {
  177. $route->isAbstract(true);
  178. }
  179. return $route;
  180. }
  181. /**
  182. * Add chain routes from a config route
  183. *
  184. * @param string $name
  185. * @param Zend_Controller_Router_Route_Interface $route
  186. * @param Zend_Config $childRoutesInfo
  187. * @return void
  188. */
  189. protected function _addChainRoutesFromConfig($name,
  190. Zend_Controller_Router_Route_Interface $route,
  191. Zend_Config $childRoutesInfo)
  192. {
  193. foreach ($childRoutesInfo as $childRouteName => $childRouteInfo) {
  194. if (is_string($childRouteInfo)) {
  195. $childRouteName = $childRouteInfo;
  196. $childRoute = $this->getRoute($childRouteName);
  197. } else {
  198. $childRoute = $this->_getRouteFromConfig($childRouteInfo);
  199. }
  200. if ($route instanceof Zend_Controller_Router_Route_Chain) {
  201. $chainRoute = clone $route;
  202. $chainRoute->chain($childRoute);
  203. } else {
  204. $chainRoute = $route->chain($childRoute);
  205. }
  206. $chainName = $name . '-' . $childRouteName;
  207. if (isset($childRouteInfo->chains)) {
  208. $this->_addChainRoutesFromConfig($chainName, $chainRoute, $childRouteInfo->chains);
  209. } else {
  210. $this->addRoute($chainName, $chainRoute);
  211. }
  212. }
  213. }
  214. /**
  215. * Remove a route from the route chain
  216. *
  217. * @param string $name Name of the route
  218. * @throws Zend_Controller_Router_Exception
  219. * @return Zend_Controller_Router_Rewrite
  220. */
  221. public function removeRoute($name)
  222. {
  223. if (!isset($this->_routes[$name])) {
  224. require_once 'Zend/Controller/Router/Exception.php';
  225. throw new Zend_Controller_Router_Exception("Route $name is not defined");
  226. }
  227. unset($this->_routes[$name]);
  228. return $this;
  229. }
  230. /**
  231. * Remove all standard default routes
  232. *
  233. * @param Zend_Controller_Router_Route_Interface Route
  234. * @return Zend_Controller_Router_Rewrite
  235. */
  236. public function removeDefaultRoutes()
  237. {
  238. $this->_useDefaultRoutes = false;
  239. return $this;
  240. }
  241. /**
  242. * Check if named route exists
  243. *
  244. * @param string $name Name of the route
  245. * @return boolean
  246. */
  247. public function hasRoute($name)
  248. {
  249. return isset($this->_routes[$name]);
  250. }
  251. /**
  252. * Retrieve a named route
  253. *
  254. * @param string $name Name of the route
  255. * @throws Zend_Controller_Router_Exception
  256. * @return Zend_Controller_Router_Route_Interface Route object
  257. */
  258. public function getRoute($name)
  259. {
  260. if (!isset($this->_routes[$name])) {
  261. require_once 'Zend/Controller/Router/Exception.php';
  262. throw new Zend_Controller_Router_Exception("Route $name is not defined");
  263. }
  264. return $this->_routes[$name];
  265. }
  266. /**
  267. * Retrieve a currently matched route
  268. *
  269. * @throws Zend_Controller_Router_Exception
  270. * @return Zend_Controller_Router_Route_Interface Route object
  271. */
  272. public function getCurrentRoute()
  273. {
  274. if (!isset($this->_currentRoute)) {
  275. require_once 'Zend/Controller/Router/Exception.php';
  276. throw new Zend_Controller_Router_Exception("Current route is not defined");
  277. }
  278. return $this->getRoute($this->_currentRoute);
  279. }
  280. /**
  281. * Retrieve a name of currently matched route
  282. *
  283. * @throws Zend_Controller_Router_Exception
  284. * @return Zend_Controller_Router_Route_Interface Route object
  285. */
  286. public function getCurrentRouteName()
  287. {
  288. if (!isset($this->_currentRoute)) {
  289. require_once 'Zend/Controller/Router/Exception.php';
  290. throw new Zend_Controller_Router_Exception("Current route is not defined");
  291. }
  292. return $this->_currentRoute;
  293. }
  294. /**
  295. * Retrieve an array of routes added to the route chain
  296. *
  297. * @return array All of the defined routes
  298. */
  299. public function getRoutes()
  300. {
  301. return $this->_routes;
  302. }
  303. /**
  304. * Find a matching route to the current PATH_INFO and inject
  305. * returning values to the Request object.
  306. *
  307. * @throws Zend_Controller_Router_Exception
  308. * @return Zend_Controller_Request_Abstract Request object
  309. */
  310. public function route(Zend_Controller_Request_Abstract $request)
  311. {
  312. if (!$request instanceof Zend_Controller_Request_Http) {
  313. require_once 'Zend/Controller/Router/Exception.php';
  314. throw new Zend_Controller_Router_Exception('Zend_Controller_Router_Rewrite requires a Zend_Controller_Request_Http-based request object');
  315. }
  316. if ($this->_useDefaultRoutes) {
  317. $this->addDefaultRoutes();
  318. }
  319. // Find the matching route
  320. foreach (array_reverse($this->_routes) as $name => $route) {
  321. // TODO: Should be an interface method. Hack for 1.0 BC
  322. if (method_exists($route, 'isAbstract') && $route->isAbstract()) {
  323. continue;
  324. }
  325. // TODO: Should be an interface method. Hack for 1.0 BC
  326. if (!method_exists($route, 'getVersion') || $route->getVersion() == 1) {
  327. $match = $request->getPathInfo();
  328. } else {
  329. $match = $request;
  330. }
  331. if ($params = $route->match($match)) {
  332. $this->_setRequestParams($request, $params);
  333. $this->_currentRoute = $name;
  334. break;
  335. }
  336. }
  337. return $request;
  338. }
  339. protected function _setRequestParams($request, $params)
  340. {
  341. foreach ($params as $param => $value) {
  342. $request->setParam($param, $value);
  343. if ($param === $request->getModuleKey()) {
  344. $request->setModuleName($value);
  345. }
  346. if ($param === $request->getControllerKey()) {
  347. $request->setControllerName($value);
  348. }
  349. if ($param === $request->getActionKey()) {
  350. $request->setActionName($value);
  351. }
  352. }
  353. }
  354. /**
  355. * Generates a URL path that can be used in URL creation, redirection, etc.
  356. *
  357. * @param array $userParams Options passed by a user used to override parameters
  358. * @param mixed $name The name of a Route to use
  359. * @param bool $reset Whether to reset to the route defaults ignoring URL params
  360. * @param bool $encode Tells to encode URL parts on output
  361. * @throws Zend_Controller_Router_Exception
  362. * @return string Resulting absolute URL path
  363. */
  364. public function assemble($userParams, $name = null, $reset = false, $encode = true)
  365. {
  366. if ($name == null) {
  367. try {
  368. $name = $this->getCurrentRouteName();
  369. } catch (Zend_Controller_Router_Exception $e) {
  370. $name = 'default';
  371. }
  372. }
  373. $params = array_merge($this->_globalParams, $userParams);
  374. $route = $this->getRoute($name);
  375. $url = $route->assemble($params, $reset, $encode);
  376. if (!preg_match('|^[a-z]+://|', $url)) {
  377. $url = rtrim($this->getFrontController()->getBaseUrl(), '/') . '/' . $url;
  378. }
  379. return $url;
  380. }
  381. /**
  382. * Set a global parameter
  383. *
  384. * @param string $name
  385. * @param mixed $value
  386. * @return Zend_Controller_Router_Rewrite
  387. */
  388. public function setGlobalParam($name, $value)
  389. {
  390. $this->_globalParams[$name] = $value;
  391. return $this;
  392. }
  393. }