PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Zend/Controller/Dispatcher/Standard.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 499 lines | 404 code | 17 blank | 78 comment | 13 complexity | e964760bfa9c6ee2e18a62931bfd0033 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  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 Dispatcher
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Standard.php 22038 2010-04-28 18:54:22Z matthew $
  21. */
  22. /** Zend_Loader */
  23. #require_once 'Zend/Loader.php';
  24. /** Zend_Controller_Dispatcher_Abstract */
  25. #require_once 'Zend/Controller/Dispatcher/Abstract.php';
  26. /**
  27. * @category Zend
  28. * @package Zend_Controller
  29. * @subpackage Dispatcher
  30. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. */
  33. class Zend_Controller_Dispatcher_Standard extends Zend_Controller_Dispatcher_Abstract
  34. {
  35. /**
  36. * Current dispatchable directory
  37. * @var string
  38. */
  39. protected $_curDirectory;
  40. /**
  41. * Current module (formatted)
  42. * @var string
  43. */
  44. protected $_curModule;
  45. /**
  46. * Controller directory(ies)
  47. * @var array
  48. */
  49. protected $_controllerDirectory = array();
  50. /**
  51. * Constructor: Set current module to default value
  52. *
  53. * @param array $params
  54. * @return void
  55. */
  56. public function __construct(array $params = array())
  57. {
  58. parent::__construct($params);
  59. $this->_curModule = $this->getDefaultModule();
  60. }
  61. /**
  62. * Add a single path to the controller directory stack
  63. *
  64. * @param string $path
  65. * @param string $module
  66. * @return Zend_Controller_Dispatcher_Standard
  67. */
  68. public function addControllerDirectory($path, $module = null)
  69. {
  70. if (null === $module) {
  71. $module = $this->_defaultModule;
  72. }
  73. $module = (string) $module;
  74. $path = rtrim((string) $path, '/\\');
  75. $this->_controllerDirectory[$module] = $path;
  76. return $this;
  77. }
  78. /**
  79. * Set controller directory
  80. *
  81. * @param array|string $directory
  82. * @return Zend_Controller_Dispatcher_Standard
  83. */
  84. public function setControllerDirectory($directory, $module = null)
  85. {
  86. $this->_controllerDirectory = array();
  87. if (is_string($directory)) {
  88. $this->addControllerDirectory($directory, $module);
  89. } elseif (is_array($directory)) {
  90. foreach ((array) $directory as $module => $path) {
  91. $this->addControllerDirectory($path, $module);
  92. }
  93. } else {
  94. #require_once 'Zend/Controller/Exception.php';
  95. throw new Zend_Controller_Exception('Controller directory spec must be either a string or an array');
  96. }
  97. return $this;
  98. }
  99. /**
  100. * Return the currently set directories for Zend_Controller_Action class
  101. * lookup
  102. *
  103. * If a module is specified, returns just that directory.
  104. *
  105. * @param string $module Module name
  106. * @return array|string Returns array of all directories by default, single
  107. * module directory if module argument provided
  108. */
  109. public function getControllerDirectory($module = null)
  110. {
  111. if (null === $module) {
  112. return $this->_controllerDirectory;
  113. }
  114. $module = (string) $module;
  115. if (array_key_exists($module, $this->_controllerDirectory)) {
  116. return $this->_controllerDirectory[$module];
  117. }
  118. return null;
  119. }
  120. /**
  121. * Remove a controller directory by module name
  122. *
  123. * @param string $module
  124. * @return bool
  125. */
  126. public function removeControllerDirectory($module)
  127. {
  128. $module = (string) $module;
  129. if (array_key_exists($module, $this->_controllerDirectory)) {
  130. unset($this->_controllerDirectory[$module]);
  131. return true;
  132. }
  133. return false;
  134. }
  135. /**
  136. * Format the module name.
  137. *
  138. * @param string $unformatted
  139. * @return string
  140. */
  141. public function formatModuleName($unformatted)
  142. {
  143. if (($this->_defaultModule == $unformatted) && !$this->getParam('prefixDefaultModule')) {
  144. return $unformatted;
  145. }
  146. return ucfirst($this->_formatName($unformatted));
  147. }
  148. /**
  149. * Format action class name
  150. *
  151. * @param string $moduleName Name of the current module
  152. * @param string $className Name of the action class
  153. * @return string Formatted class name
  154. */
  155. public function formatClassName($moduleName, $className)
  156. {
  157. return $this->formatModuleName($moduleName) . '_' . $className;
  158. }
  159. /**
  160. * Convert a class name to a filename
  161. *
  162. * @param string $class
  163. * @return string
  164. */
  165. public function classToFilename($class)
  166. {
  167. return str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
  168. }
  169. /**
  170. * Returns TRUE if the Zend_Controller_Request_Abstract object can be
  171. * dispatched to a controller.
  172. *
  173. * Use this method wisely. By default, the dispatcher will fall back to the
  174. * default controller (either in the module specified or the global default)
  175. * if a given controller does not exist. This method returning false does
  176. * not necessarily indicate the dispatcher will not still dispatch the call.
  177. *
  178. * @param Zend_Controller_Request_Abstract $action
  179. * @return boolean
  180. */
  181. public function isDispatchable(Zend_Controller_Request_Abstract $request)
  182. {
  183. $className = $this->getControllerClass($request);
  184. if (!$className) {
  185. return false;
  186. }
  187. $finalClass = $className;
  188. if (($this->_defaultModule != $this->_curModule)
  189. || $this->getParam('prefixDefaultModule'))
  190. {
  191. $finalClass = $this->formatClassName($this->_curModule, $className);
  192. }
  193. if (class_exists($finalClass, false)) {
  194. return true;
  195. }
  196. $fileSpec = $this->classToFilename($className);
  197. $dispatchDir = $this->getDispatchDirectory();
  198. $test = $dispatchDir . DIRECTORY_SEPARATOR . $fileSpec;
  199. return Zend_Loader::isReadable($test);
  200. }
  201. /**
  202. * Dispatch to a controller/action
  203. *
  204. * By default, if a controller is not dispatchable, dispatch() will throw
  205. * an exception. If you wish to use the default controller instead, set the
  206. * param 'useDefaultControllerAlways' via {@link setParam()}.
  207. *
  208. * @param Zend_Controller_Request_Abstract $request
  209. * @param Zend_Controller_Response_Abstract $response
  210. * @return void
  211. * @throws Zend_Controller_Dispatcher_Exception
  212. */
  213. public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response)
  214. {
  215. $this->setResponse($response);
  216. /**
  217. * Get controller class
  218. */
  219. if (!$this->isDispatchable($request)) {
  220. $controller = $request->getControllerName();
  221. if (!$this->getParam('useDefaultControllerAlways') && !empty($controller)) {
  222. #require_once 'Zend/Controller/Dispatcher/Exception.php';
  223. throw new Zend_Controller_Dispatcher_Exception('Invalid controller specified (' . $request->getControllerName() . ')');
  224. }
  225. $className = $this->getDefaultControllerClass($request);
  226. } else {
  227. $className = $this->getControllerClass($request);
  228. if (!$className) {
  229. $className = $this->getDefaultControllerClass($request);
  230. }
  231. }
  232. /**
  233. * Load the controller class file
  234. */
  235. $className = $this->loadClass($className);
  236. /**
  237. * Instantiate controller with request, response, and invocation
  238. * arguments; throw exception if it's not an action controller
  239. */
  240. $controller = new $className($request, $this->getResponse(), $this->getParams());
  241. if (!($controller instanceof Zend_Controller_Action_Interface) &&
  242. !($controller instanceof Zend_Controller_Action)) {
  243. #require_once 'Zend/Controller/Dispatcher/Exception.php';
  244. throw new Zend_Controller_Dispatcher_Exception(
  245. 'Controller "' . $className . '" is not an instance of Zend_Controller_Action_Interface'
  246. );
  247. }
  248. /**
  249. * Retrieve the action name
  250. */
  251. $action = $this->getActionMethod($request);
  252. /**
  253. * Dispatch the method call
  254. */
  255. $request->setDispatched(true);
  256. // by default, buffer output
  257. $disableOb = $this->getParam('disableOutputBuffering');
  258. $obLevel = ob_get_level();
  259. if (empty($disableOb)) {
  260. ob_start();
  261. }
  262. try {
  263. $controller->dispatch($action);
  264. } catch (Exception $e) {
  265. // Clean output buffer on error
  266. $curObLevel = ob_get_level();
  267. if ($curObLevel > $obLevel) {
  268. do {
  269. ob_get_clean();
  270. $curObLevel = ob_get_level();
  271. } while ($curObLevel > $obLevel);
  272. }
  273. throw $e;
  274. }
  275. if (empty($disableOb)) {
  276. $content = ob_get_clean();
  277. $response->appendBody($content);
  278. }
  279. // Destroy the page controller instance and reflection objects
  280. $controller = null;
  281. }
  282. /**
  283. * Load a controller class
  284. *
  285. * Attempts to load the controller class file from
  286. * {@link getControllerDirectory()}. If the controller belongs to a
  287. * module, looks for the module prefix to the controller class.
  288. *
  289. * @param string $className
  290. * @return string Class name loaded
  291. * @throws Zend_Controller_Dispatcher_Exception if class not loaded
  292. */
  293. public function loadClass($className)
  294. {
  295. $finalClass = $className;
  296. if (($this->_defaultModule != $this->_curModule)
  297. || $this->getParam('prefixDefaultModule'))
  298. {
  299. $finalClass = $this->formatClassName($this->_curModule, $className);
  300. }
  301. if (class_exists($finalClass, false)) {
  302. return $finalClass;
  303. }
  304. $dispatchDir = $this->getDispatchDirectory();
  305. $loadFile = $dispatchDir . DIRECTORY_SEPARATOR . $this->classToFilename($className);
  306. if (Zend_Loader::isReadable($loadFile)) {
  307. include_once $loadFile;
  308. } else {
  309. #require_once 'Zend/Controller/Dispatcher/Exception.php';
  310. throw new Zend_Controller_Dispatcher_Exception('Cannot load controller class "' . $className . '" from file "' . $loadFile . "'");
  311. }
  312. if (!class_exists($finalClass, false)) {
  313. #require_once 'Zend/Controller/Dispatcher/Exception.php';
  314. throw new Zend_Controller_Dispatcher_Exception('Invalid controller class ("' . $finalClass . '")');
  315. }
  316. return $finalClass;
  317. }
  318. /**
  319. * Get controller class name
  320. *
  321. * Try request first; if not found, try pulling from request parameter;
  322. * if still not found, fallback to default
  323. *
  324. * @param Zend_Controller_Request_Abstract $request
  325. * @return string|false Returns class name on success
  326. */
  327. public function getControllerClass(Zend_Controller_Request_Abstract $request)
  328. {
  329. $controllerName = $request->getControllerName();
  330. if (empty($controllerName)) {
  331. if (!$this->getParam('useDefaultControllerAlways')) {
  332. return false;
  333. }
  334. $controllerName = $this->getDefaultControllerName();
  335. $request->setControllerName($controllerName);
  336. }
  337. $className = $this->formatControllerName($controllerName);
  338. $controllerDirs = $this->getControllerDirectory();
  339. $module = $request->getModuleName();
  340. if ($this->isValidModule($module)) {
  341. $this->_curModule = $module;
  342. $this->_curDirectory = $controllerDirs[$module];
  343. } elseif ($this->isValidModule($this->_defaultModule)) {
  344. $request->setModuleName($this->_defaultModule);
  345. $this->_curModule = $this->_defaultModule;
  346. $this->_curDirectory = $controllerDirs[$this->_defaultModule];
  347. } else {
  348. #require_once 'Zend/Controller/Exception.php';
  349. throw new Zend_Controller_Exception('No default module defined for this application');
  350. }
  351. return $className;
  352. }
  353. /**
  354. * Determine if a given module is valid
  355. *
  356. * @param string $module
  357. * @return bool
  358. */
  359. public function isValidModule($module)
  360. {
  361. if (!is_string($module)) {
  362. return false;
  363. }
  364. $module = strtolower($module);
  365. $controllerDir = $this->getControllerDirectory();
  366. foreach (array_keys($controllerDir) as $moduleName) {
  367. if ($module == strtolower($moduleName)) {
  368. return true;
  369. }
  370. }
  371. return false;
  372. }
  373. /**
  374. * Retrieve default controller class
  375. *
  376. * Determines whether the default controller to use lies within the
  377. * requested module, or if the global default should be used.
  378. *
  379. * By default, will only use the module default unless that controller does
  380. * not exist; if this is the case, it falls back to the default controller
  381. * in the default module.
  382. *
  383. * @param Zend_Controller_Request_Abstract $request
  384. * @return string
  385. */
  386. public function getDefaultControllerClass(Zend_Controller_Request_Abstract $request)
  387. {
  388. $controller = $this->getDefaultControllerName();
  389. $default = $this->formatControllerName($controller);
  390. $request->setControllerName($controller)
  391. ->setActionName(null);
  392. $module = $request->getModuleName();
  393. $controllerDirs = $this->getControllerDirectory();
  394. $this->_curModule = $this->_defaultModule;
  395. $this->_curDirectory = $controllerDirs[$this->_defaultModule];
  396. if ($this->isValidModule($module)) {
  397. $found = false;
  398. if (class_exists($default, false)) {
  399. $found = true;
  400. } else {
  401. $moduleDir = $controllerDirs[$module];
  402. $fileSpec = $moduleDir . DIRECTORY_SEPARATOR . $this->classToFilename($default);
  403. if (Zend_Loader::isReadable($fileSpec)) {
  404. $found = true;
  405. $this->_curDirectory = $moduleDir;
  406. }
  407. }
  408. if ($found) {
  409. $request->setModuleName($module);
  410. $this->_curModule = $this->formatModuleName($module);
  411. }
  412. } else {
  413. $request->setModuleName($this->_defaultModule);
  414. }
  415. return $default;
  416. }
  417. /**
  418. * Return the value of the currently selected dispatch directory (as set by
  419. * {@link getController()})
  420. *
  421. * @return string
  422. */
  423. public function getDispatchDirectory()
  424. {
  425. return $this->_curDirectory;
  426. }
  427. /**
  428. * Determine the action name
  429. *
  430. * First attempt to retrieve from request; then from request params
  431. * using action key; default to default action
  432. *
  433. * Returns formatted action name
  434. *
  435. * @param Zend_Controller_Request_Abstract $request
  436. * @return string
  437. */
  438. public function getActionMethod(Zend_Controller_Request_Abstract $request)
  439. {
  440. $action = $request->getActionName();
  441. if (empty($action)) {
  442. $action = $this->getDefaultAction();
  443. $request->setActionName($action);
  444. }
  445. return $this->formatActionName($action);
  446. }
  447. }