PageRenderTime 65ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/Controller/Action.php

https://bitbucket.org/luizbrandaoj/mini-blog
PHP | 692 lines | 260 code | 70 blank | 362 comment | 40 complexity | c933fb8fccd6ba1c155b7ce675673d9b 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. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Action.php 24253 2011-07-22 00:15:05Z adamlundrigan $
  20. */
  21. /**
  22. * @see Zend_Controller_Action_HelperBroker
  23. */
  24. require_once 'Zend/Controller/Action/HelperBroker.php';
  25. /**
  26. * @see Zend_Controller_Action_Interface
  27. */
  28. require_once 'Zend/Controller/Action/Interface.php';
  29. /**
  30. * @see Zend_Controller_Front
  31. */
  32. require_once 'Zend/Controller/Front.php';
  33. /**
  34. * @category Zend
  35. * @package Zend_Controller
  36. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  37. * @license http://framework.zend.com/license/new-bsd New BSD License
  38. */
  39. abstract class Zend_Controller_Action implements Zend_Controller_Action_Interface
  40. {
  41. /**
  42. * @var array of existing class methods
  43. */
  44. protected $_classMethods;
  45. /**
  46. * Word delimiters (used for normalizing view script paths)
  47. * @var array
  48. */
  49. protected $_delimiters;
  50. /**
  51. * Array of arguments provided to the constructor, minus the
  52. * {@link $_request Request object}.
  53. * @var array
  54. */
  55. protected $_invokeArgs = array();
  56. /**
  57. * Front controller instance
  58. * @var Zend_Controller_Front
  59. */
  60. protected $_frontController;
  61. /**
  62. * Zend_Controller_Request_Abstract object wrapping the request environment
  63. * @var Zend_Controller_Request_Abstract
  64. */
  65. protected $_request = null;
  66. /**
  67. * Zend_Controller_Response_Abstract object wrapping the response
  68. * @var Zend_Controller_Response_Abstract
  69. */
  70. protected $_response = null;
  71. /**
  72. * View script suffix; defaults to 'phtml'
  73. * @see {render()}
  74. * @var string
  75. */
  76. public $viewSuffix = 'phtml';
  77. /**
  78. * View object
  79. * @var Zend_View_Interface
  80. */
  81. public $view;
  82. /**
  83. * Helper Broker to assist in routing help requests to the proper object
  84. *
  85. * @var Zend_Controller_Action_HelperBroker
  86. */
  87. protected $_helper = null;
  88. /**
  89. * Class constructor
  90. *
  91. * The request and response objects should be registered with the
  92. * controller, as should be any additional optional arguments; these will be
  93. * available via {@link getRequest()}, {@link getResponse()}, and
  94. * {@link getInvokeArgs()}, respectively.
  95. *
  96. * When overriding the constructor, please consider this usage as a best
  97. * practice and ensure that each is registered appropriately; the easiest
  98. * way to do so is to simply call parent::__construct($request, $response,
  99. * $invokeArgs).
  100. *
  101. * After the request, response, and invokeArgs are set, the
  102. * {@link $_helper helper broker} is initialized.
  103. *
  104. * Finally, {@link init()} is called as the final action of
  105. * instantiation, and may be safely overridden to perform initialization
  106. * tasks; as a general rule, override {@link init()} instead of the
  107. * constructor to customize an action controller's instantiation.
  108. *
  109. * @param Zend_Controller_Request_Abstract $request
  110. * @param Zend_Controller_Response_Abstract $response
  111. * @param array $invokeArgs Any additional invocation arguments
  112. * @return void
  113. */
  114. public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
  115. {
  116. $this->setRequest($request)
  117. ->setResponse($response)
  118. ->_setInvokeArgs($invokeArgs);
  119. $this->_helper = new Zend_Controller_Action_HelperBroker($this);
  120. $this->init();
  121. }
  122. /**
  123. * Initialize object
  124. *
  125. * Called from {@link __construct()} as final step of object instantiation.
  126. *
  127. * @return void
  128. */
  129. public function init()
  130. {
  131. }
  132. /**
  133. * Initialize View object
  134. *
  135. * Initializes {@link $view} if not otherwise a Zend_View_Interface.
  136. *
  137. * If {@link $view} is not otherwise set, instantiates a new Zend_View
  138. * object, using the 'views' subdirectory at the same level as the
  139. * controller directory for the current module as the base directory.
  140. * It uses this to set the following:
  141. * - script path = views/scripts/
  142. * - helper path = views/helpers/
  143. * - filter path = views/filters/
  144. *
  145. * @return Zend_View_Interface
  146. * @throws Zend_Controller_Exception if base view directory does not exist
  147. */
  148. public function initView()
  149. {
  150. if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
  151. return $this->view;
  152. }
  153. require_once 'Zend/View/Interface.php';
  154. if (isset($this->view) && ($this->view instanceof Zend_View_Interface)) {
  155. return $this->view;
  156. }
  157. $request = $this->getRequest();
  158. $module = $request->getModuleName();
  159. $dirs = $this->getFrontController()->getControllerDirectory();
  160. if (empty($module) || !isset($dirs[$module])) {
  161. $module = $this->getFrontController()->getDispatcher()->getDefaultModule();
  162. }
  163. $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'views';
  164. if (!file_exists($baseDir) || !is_dir($baseDir)) {
  165. require_once 'Zend/Controller/Exception.php';
  166. throw new Zend_Controller_Exception('Missing base view directory ("' . $baseDir . '")');
  167. }
  168. require_once 'Zend/View.php';
  169. $this->view = new Zend_View(array('basePath' => $baseDir));
  170. return $this->view;
  171. }
  172. /**
  173. * Render a view
  174. *
  175. * Renders a view. By default, views are found in the view script path as
  176. * <controller>/<action>.phtml. You may change the script suffix by
  177. * resetting {@link $viewSuffix}. You may omit the controller directory
  178. * prefix by specifying boolean true for $noController.
  179. *
  180. * By default, the rendered contents are appended to the response. You may
  181. * specify the named body content segment to set by specifying a $name.
  182. *
  183. * @see Zend_Controller_Response_Abstract::appendBody()
  184. * @param string|null $action Defaults to action registered in request object
  185. * @param string|null $name Response object named path segment to use; defaults to null
  186. * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script
  187. * @return void
  188. */
  189. public function render($action = null, $name = null, $noController = false)
  190. {
  191. if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
  192. return $this->_helper->viewRenderer->render($action, $name, $noController);
  193. }
  194. $view = $this->initView();
  195. $script = $this->getViewScript($action, $noController);
  196. $this->getResponse()->appendBody(
  197. $view->render($script),
  198. $name
  199. );
  200. }
  201. /**
  202. * Render a given view script
  203. *
  204. * Similar to {@link render()}, this method renders a view script. Unlike render(),
  205. * however, it does not autodetermine the view script via {@link getViewScript()},
  206. * but instead renders the script passed to it. Use this if you know the
  207. * exact view script name and path you wish to use, or if using paths that do not
  208. * conform to the spec defined with getViewScript().
  209. *
  210. * By default, the rendered contents are appended to the response. You may
  211. * specify the named body content segment to set by specifying a $name.
  212. *
  213. * @param string $script
  214. * @param string $name
  215. * @return void
  216. */
  217. public function renderScript($script, $name = null)
  218. {
  219. if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
  220. return $this->_helper->viewRenderer->renderScript($script, $name);
  221. }
  222. $view = $this->initView();
  223. $this->getResponse()->appendBody(
  224. $view->render($script),
  225. $name
  226. );
  227. }
  228. /**
  229. * Construct view script path
  230. *
  231. * Used by render() to determine the path to the view script.
  232. *
  233. * @param string $action Defaults to action registered in request object
  234. * @param bool $noController Defaults to false; i.e. use controller name as subdir in which to search for view script
  235. * @return string
  236. * @throws Zend_Controller_Exception with bad $action
  237. */
  238. public function getViewScript($action = null, $noController = null)
  239. {
  240. if (!$this->getInvokeArg('noViewRenderer') && $this->_helper->hasHelper('viewRenderer')) {
  241. $viewRenderer = $this->_helper->getHelper('viewRenderer');
  242. if (null !== $noController) {
  243. $viewRenderer->setNoController($noController);
  244. }
  245. return $viewRenderer->getViewScript($action);
  246. }
  247. $request = $this->getRequest();
  248. if (null === $action) {
  249. $action = $request->getActionName();
  250. } elseif (!is_string($action)) {
  251. require_once 'Zend/Controller/Exception.php';
  252. throw new Zend_Controller_Exception('Invalid action specifier for view render');
  253. }
  254. if (null === $this->_delimiters) {
  255. $dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
  256. $wordDelimiters = $dispatcher->getWordDelimiter();
  257. $pathDelimiters = $dispatcher->getPathDelimiter();
  258. $this->_delimiters = array_unique(array_merge($wordDelimiters, (array) $pathDelimiters));
  259. }
  260. $action = str_replace($this->_delimiters, '-', $action);
  261. $script = $action . '.' . $this->viewSuffix;
  262. if (!$noController) {
  263. $controller = $request->getControllerName();
  264. $controller = str_replace($this->_delimiters, '-', $controller);
  265. $script = $controller . DIRECTORY_SEPARATOR . $script;
  266. }
  267. return $script;
  268. }
  269. /**
  270. * Return the Request object
  271. *
  272. * @return Zend_Controller_Request_Abstract
  273. */
  274. public function getRequest()
  275. {
  276. return $this->_request;
  277. }
  278. /**
  279. * Set the Request object
  280. *
  281. * @param Zend_Controller_Request_Abstract $request
  282. * @return Zend_Controller_Action
  283. */
  284. public function setRequest(Zend_Controller_Request_Abstract $request)
  285. {
  286. $this->_request = $request;
  287. return $this;
  288. }
  289. /**
  290. * Return the Response object
  291. *
  292. * @return Zend_Controller_Response_Abstract
  293. */
  294. public function getResponse()
  295. {
  296. return $this->_response;
  297. }
  298. /**
  299. * Set the Response object
  300. *
  301. * @param Zend_Controller_Response_Abstract $response
  302. * @return Zend_Controller_Action
  303. */
  304. public function setResponse(Zend_Controller_Response_Abstract $response)
  305. {
  306. $this->_response = $response;
  307. return $this;
  308. }
  309. /**
  310. * Set invocation arguments
  311. *
  312. * @param array $args
  313. * @return Zend_Controller_Action
  314. */
  315. protected function _setInvokeArgs(array $args = array())
  316. {
  317. $this->_invokeArgs = $args;
  318. return $this;
  319. }
  320. /**
  321. * Return the array of constructor arguments (minus the Request object)
  322. *
  323. * @return array
  324. */
  325. public function getInvokeArgs()
  326. {
  327. return $this->_invokeArgs;
  328. }
  329. /**
  330. * Return a single invocation argument
  331. *
  332. * @param string $key
  333. * @return mixed
  334. */
  335. public function getInvokeArg($key)
  336. {
  337. if (isset($this->_invokeArgs[$key])) {
  338. return $this->_invokeArgs[$key];
  339. }
  340. return null;
  341. }
  342. /**
  343. * Get a helper by name
  344. *
  345. * @param string $helperName
  346. * @return Zend_Controller_Action_Helper_Abstract
  347. */
  348. public function getHelper($helperName)
  349. {
  350. return $this->_helper->{$helperName};
  351. }
  352. /**
  353. * Get a clone of a helper by name
  354. *
  355. * @param string $helperName
  356. * @return Zend_Controller_Action_Helper_Abstract
  357. */
  358. public function getHelperCopy($helperName)
  359. {
  360. return clone $this->_helper->{$helperName};
  361. }
  362. /**
  363. * Set the front controller instance
  364. *
  365. * @param Zend_Controller_Front $front
  366. * @return Zend_Controller_Action
  367. */
  368. public function setFrontController(Zend_Controller_Front $front)
  369. {
  370. $this->_frontController = $front;
  371. return $this;
  372. }
  373. /**
  374. * Retrieve Front Controller
  375. *
  376. * @return Zend_Controller_Front
  377. */
  378. public function getFrontController()
  379. {
  380. // Used cache version if found
  381. if (null !== $this->_frontController) {
  382. return $this->_frontController;
  383. }
  384. // Grab singleton instance, if class has been loaded
  385. if (class_exists('Zend_Controller_Front')) {
  386. $this->_frontController = Zend_Controller_Front::getInstance();
  387. return $this->_frontController;
  388. }
  389. // Throw exception in all other cases
  390. require_once 'Zend/Controller/Exception.php';
  391. throw new Zend_Controller_Exception('Front controller class has not been loaded');
  392. }
  393. /**
  394. * Pre-dispatch routines
  395. *
  396. * Called before action method. If using class with
  397. * {@link Zend_Controller_Front}, it may modify the
  398. * {@link $_request Request object} and reset its dispatched flag in order
  399. * to skip processing the current action.
  400. *
  401. * @return void
  402. */
  403. public function preDispatch()
  404. {
  405. }
  406. /**
  407. * Post-dispatch routines
  408. *
  409. * Called after action method execution. If using class with
  410. * {@link Zend_Controller_Front}, it may modify the
  411. * {@link $_request Request object} and reset its dispatched flag in order
  412. * to process an additional action.
  413. *
  414. * Common usages for postDispatch() include rendering content in a sitewide
  415. * template, link url correction, setting headers, etc.
  416. *
  417. * @return void
  418. */
  419. public function postDispatch()
  420. {
  421. }
  422. /**
  423. * Proxy for undefined methods. Default behavior is to throw an
  424. * exception on undefined methods, however this function can be
  425. * overridden to implement magic (dynamic) actions, or provide run-time
  426. * dispatching.
  427. *
  428. * @param string $methodName
  429. * @param array $args
  430. * @return void
  431. * @throws Zend_Controller_Action_Exception
  432. */
  433. public function __call($methodName, $args)
  434. {
  435. require_once 'Zend/Controller/Action/Exception.php';
  436. if ('Action' == substr($methodName, -6)) {
  437. $action = substr($methodName, 0, strlen($methodName) - 6);
  438. throw new Zend_Controller_Action_Exception(sprintf('Action "%s" does not exist and was not trapped in __call()', $action), 404);
  439. }
  440. throw new Zend_Controller_Action_Exception(sprintf('Method "%s" does not exist and was not trapped in __call()', $methodName), 500);
  441. }
  442. /**
  443. * Dispatch the requested action
  444. *
  445. * @param string $action Method name of action
  446. * @return void
  447. */
  448. public function dispatch($action)
  449. {
  450. // Notify helpers of action preDispatch state
  451. $this->_helper->notifyPreDispatch();
  452. $this->preDispatch();
  453. if ($this->getRequest()->isDispatched()) {
  454. if (null === $this->_classMethods) {
  455. $this->_classMethods = get_class_methods($this);
  456. }
  457. // If pre-dispatch hooks introduced a redirect then stop dispatch
  458. // @see ZF-7496
  459. if (!($this->getResponse()->isRedirect())) {
  460. // preDispatch() didn't change the action, so we can continue
  461. if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
  462. if ($this->getInvokeArg('useCaseSensitiveActions')) {
  463. trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
  464. }
  465. $this->$action();
  466. } else {
  467. $this->__call($action, array());
  468. }
  469. }
  470. $this->postDispatch();
  471. }
  472. // whats actually important here is that this action controller is
  473. // shutting down, regardless of dispatching; notify the helpers of this
  474. // state
  475. $this->_helper->notifyPostDispatch();
  476. }
  477. /**
  478. * Call the action specified in the request object, and return a response
  479. *
  480. * Not used in the Action Controller implementation, but left for usage in
  481. * Page Controller implementations. Dispatches a method based on the
  482. * request.
  483. *
  484. * Returns a Zend_Controller_Response_Abstract object, instantiating one
  485. * prior to execution if none exists in the controller.
  486. *
  487. * {@link preDispatch()} is called prior to the action,
  488. * {@link postDispatch()} is called following it.
  489. *
  490. * @param null|Zend_Controller_Request_Abstract $request Optional request
  491. * object to use
  492. * @param null|Zend_Controller_Response_Abstract $response Optional response
  493. * object to use
  494. * @return Zend_Controller_Response_Abstract
  495. */
  496. public function run(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)
  497. {
  498. if (null !== $request) {
  499. $this->setRequest($request);
  500. } else {
  501. $request = $this->getRequest();
  502. }
  503. if (null !== $response) {
  504. $this->setResponse($response);
  505. }
  506. $action = $request->getActionName();
  507. if (empty($action)) {
  508. $action = 'index';
  509. }
  510. $action = $action . 'Action';
  511. $request->setDispatched(true);
  512. $this->dispatch($action);
  513. return $this->getResponse();
  514. }
  515. /**
  516. * Gets a parameter from the {@link $_request Request object}. If the
  517. * parameter does not exist, NULL will be returned.
  518. *
  519. * If the parameter does not exist and $default is set, then
  520. * $default will be returned instead of NULL.
  521. *
  522. * @param string $paramName
  523. * @param mixed $default
  524. * @return mixed
  525. */
  526. protected function _getParam($paramName, $default = null)
  527. {
  528. $value = $this->getRequest()->getParam($paramName);
  529. if ((null === $value || '' === $value) && (null !== $default)) {
  530. $value = $default;
  531. }
  532. return $value;
  533. }
  534. /**
  535. * Set a parameter in the {@link $_request Request object}.
  536. *
  537. * @param string $paramName
  538. * @param mixed $value
  539. * @return Zend_Controller_Action
  540. */
  541. protected function _setParam($paramName, $value)
  542. {
  543. $this->getRequest()->setParam($paramName, $value);
  544. return $this;
  545. }
  546. /**
  547. * Determine whether a given parameter exists in the
  548. * {@link $_request Request object}.
  549. *
  550. * @param string $paramName
  551. * @return boolean
  552. */
  553. protected function _hasParam($paramName)
  554. {
  555. return null !== $this->getRequest()->getParam($paramName);
  556. }
  557. /**
  558. * Return all parameters in the {@link $_request Request object}
  559. * as an associative array.
  560. *
  561. * @return array
  562. */
  563. protected function _getAllParams()
  564. {
  565. return $this->getRequest()->getParams();
  566. }
  567. /**
  568. * Forward to another controller/action.
  569. *
  570. * It is important to supply the unformatted names, i.e. "article"
  571. * rather than "ArticleController". The dispatcher will do the
  572. * appropriate formatting when the request is received.
  573. *
  574. * If only an action name is provided, forwards to that action in this
  575. * controller.
  576. *
  577. * If an action and controller are specified, forwards to that action and
  578. * controller in this module.
  579. *
  580. * Specifying an action, controller, and module is the most specific way to
  581. * forward.
  582. *
  583. * A fourth argument, $params, will be used to set the request parameters.
  584. * If either the controller or module are unnecessary for forwarding,
  585. * simply pass null values for them before specifying the parameters.
  586. *
  587. * @param string $action
  588. * @param string $controller
  589. * @param string $module
  590. * @param array $params
  591. * @return void
  592. */
  593. final protected function _forward($action, $controller = null, $module = null, array $params = null)
  594. {
  595. $request = $this->getRequest();
  596. if (null !== $params) {
  597. $request->setParams($params);
  598. }
  599. if (null !== $controller) {
  600. $request->setControllerName($controller);
  601. // Module should only be reset if controller has been specified
  602. if (null !== $module) {
  603. $request->setModuleName($module);
  604. }
  605. }
  606. $request->setActionName($action)
  607. ->setDispatched(false);
  608. }
  609. /**
  610. * Redirect to another URL
  611. *
  612. * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}.
  613. *
  614. * @param string $url
  615. * @param array $options Options to be used when redirecting
  616. * @return void
  617. */
  618. protected function _redirect($url, array $options = array())
  619. {
  620. $this->_helper->redirector->gotoUrl($url, $options);
  621. }
  622. }