PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/server/library/Zend/Controller/Router/Rewrite.php

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