PageRenderTime 44ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/app/code/core/Mage/Core/Controller/Varien/Action.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 1049 lines | 612 code | 117 blank | 320 comment | 98 complexity | 16f688ab0c082fc37bbcbf623eb4e593 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  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@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Core
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Custom Zend_Controller_Action class (formally)
  28. *
  29. * Allows dispatching before and after events for each controller action
  30. *
  31. * @category Mage
  32. * @package Mage_Core
  33. * @author Magento Core Team <core@magentocommerce.com>
  34. */
  35. abstract class Mage_Core_Controller_Varien_Action
  36. {
  37. const FLAG_NO_CHECK_INSTALLATION = 'no-install-check';
  38. const FLAG_NO_DISPATCH = 'no-dispatch';
  39. const FLAG_NO_PRE_DISPATCH = 'no-preDispatch';
  40. const FLAG_NO_POST_DISPATCH = 'no-postDispatch';
  41. const FLAG_NO_START_SESSION = 'no-startSession';
  42. const FLAG_NO_DISPATCH_BLOCK_EVENT = 'no-beforeGenerateLayoutBlocksDispatch';
  43. const FLAG_NO_COOKIES_REDIRECT = 'no-cookies-redirect';
  44. const PARAM_NAME_SUCCESS_URL = 'success_url';
  45. const PARAM_NAME_ERROR_URL = 'error_url';
  46. const PARAM_NAME_REFERER_URL = 'referer_url';
  47. const PARAM_NAME_BASE64_URL = 'r64';
  48. const PARAM_NAME_URL_ENCODED = 'uenc';
  49. const PROFILER_KEY = 'mage::dispatch::controller::action';
  50. /**
  51. * Request object
  52. *
  53. * @var Zend_Controller_Request_Abstract
  54. */
  55. protected $_request;
  56. /**
  57. * Response object
  58. *
  59. * @var Zend_Controller_Response_Abstract
  60. */
  61. protected $_response;
  62. /**
  63. * Real module name (like 'Mage_Module')
  64. *
  65. * @var string
  66. */
  67. protected $_realModuleName;
  68. /**
  69. * Action flags
  70. *
  71. * for example used to disable rendering default layout
  72. *
  73. * @var array
  74. */
  75. protected $_flags = array();
  76. /**
  77. * Action list where need check enabled cookie
  78. *
  79. * @var array
  80. */
  81. protected $_cookieCheckActions = array();
  82. /**
  83. * Currently used area
  84. *
  85. * @var string
  86. */
  87. protected $_currentArea;
  88. /**
  89. * Namespace for session.
  90. * Should be defined for proper working session.
  91. *
  92. * @var string
  93. */
  94. protected $_sessionNamespace;
  95. /**
  96. * Whether layout is loaded
  97. *
  98. * @see self::loadLayout()
  99. * @var bool
  100. */
  101. protected $_isLayoutLoaded = false;
  102. /**
  103. * Title parts to be rendered in the page head title
  104. *
  105. * @see self::_title()
  106. * @var array
  107. */
  108. protected $_titles = array();
  109. /**
  110. * Whether the default title should be removed
  111. *
  112. * @see self::_title()
  113. * @var bool
  114. */
  115. protected $_removeDefaultTitle = false;
  116. /**
  117. * Constructor
  118. *
  119. * @param Zend_Controller_Request_Abstract $request
  120. * @param Zend_Controller_Response_Abstract $response
  121. * @param array $invokeArgs
  122. */
  123. public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
  124. {
  125. $this->_request = $request;
  126. $this->_response= $response;
  127. Mage::app()->getFrontController()->setAction($this);
  128. $this->_construct();
  129. }
  130. protected function _construct()
  131. {
  132. }
  133. public function hasAction($action)
  134. {
  135. return is_callable(array($this, $this->getActionMethodName($action)));
  136. }
  137. /**
  138. * Retrieve request object
  139. *
  140. * @return Mage_Core_Controller_Request_Http
  141. */
  142. public function getRequest()
  143. {
  144. return $this->_request;
  145. }
  146. /**
  147. * Retrieve response object
  148. *
  149. * @return Mage_Core_Controller_Response_Http
  150. */
  151. public function getResponse()
  152. {
  153. return $this->_response;
  154. }
  155. /**
  156. * Retrieve flag value
  157. *
  158. * @param string $action
  159. * @param string $flag
  160. * @return bool
  161. */
  162. public function getFlag($action, $flag='')
  163. {
  164. if (''===$action) {
  165. $action = $this->getRequest()->getActionName();
  166. }
  167. if (''===$flag) {
  168. return $this->_flags;
  169. }
  170. elseif (isset($this->_flags[$action][$flag])) {
  171. return $this->_flags[$action][$flag];
  172. }
  173. else {
  174. return false;
  175. }
  176. }
  177. /**
  178. * Setting flag value
  179. *
  180. * @param string $action
  181. * @param string $flag
  182. * @param string $value
  183. * @return Mage_Core_Controller_Varien_Action
  184. */
  185. public function setFlag($action, $flag, $value)
  186. {
  187. if (''===$action) {
  188. $action = $this->getRequest()->getActionName();
  189. }
  190. $this->_flags[$action][$flag] = $value;
  191. return $this;
  192. }
  193. /**
  194. * Retrieve full bane of current action current controller and
  195. * current module
  196. *
  197. * @param string $delimiter
  198. * @return string
  199. */
  200. public function getFullActionName($delimiter='_')
  201. {
  202. return $this->getRequest()->getRequestedRouteName().$delimiter.
  203. $this->getRequest()->getRequestedControllerName().$delimiter.
  204. $this->getRequest()->getRequestedActionName();
  205. }
  206. /**
  207. * Retrieve current layout object
  208. *
  209. * @return Mage_Core_Model_Layout
  210. */
  211. public function getLayout()
  212. {
  213. return Mage::getSingleton('core/layout');
  214. }
  215. /**
  216. * Load layout by handles(s)
  217. *
  218. * @param string $handles
  219. * @param string $cacheId
  220. * @param boolean $generateBlocks
  221. * @return Mage_Core_Controller_Varien_Action
  222. */
  223. public function loadLayout($handles=null, $generateBlocks=true, $generateXml=true)
  224. {
  225. // if handles were specified in arguments load them first
  226. if (false!==$handles && ''!==$handles) {
  227. $this->getLayout()->getUpdate()->addHandle($handles ? $handles : 'default');
  228. }
  229. // add default layout handles for this action
  230. $this->addActionLayoutHandles();
  231. $this->loadLayoutUpdates();
  232. if (!$generateXml) {
  233. return $this;
  234. }
  235. $this->generateLayoutXml();
  236. if (!$generateBlocks) {
  237. return $this;
  238. }
  239. $this->generateLayoutBlocks();
  240. $this->_isLayoutLoaded = true;
  241. return $this;
  242. }
  243. public function addActionLayoutHandles()
  244. {
  245. $update = $this->getLayout()->getUpdate();
  246. // load store handle
  247. $update->addHandle('STORE_'.Mage::app()->getStore()->getCode());
  248. // load theme handle
  249. $package = Mage::getSingleton('core/design_package');
  250. $update->addHandle(
  251. 'THEME_'.$package->getArea().'_'.$package->getPackageName().'_'.$package->getTheme('layout')
  252. );
  253. // load action handle
  254. $update->addHandle(strtolower($this->getFullActionName()));
  255. return $this;
  256. }
  257. public function loadLayoutUpdates()
  258. {
  259. $_profilerKey = self::PROFILER_KEY . '::' .$this->getFullActionName();
  260. // dispatch event for adding handles to layout update
  261. Mage::dispatchEvent(
  262. 'controller_action_layout_load_before',
  263. array('action'=>$this, 'layout'=>$this->getLayout())
  264. );
  265. // load layout updates by specified handles
  266. Varien_Profiler::start("$_profilerKey::layout_load");
  267. $this->getLayout()->getUpdate()->load();
  268. Varien_Profiler::stop("$_profilerKey::layout_load");
  269. return $this;
  270. }
  271. public function generateLayoutXml()
  272. {
  273. $_profilerKey = self::PROFILER_KEY . '::' . $this->getFullActionName();
  274. // dispatch event for adding text layouts
  275. if(!$this->getFlag('', self::FLAG_NO_DISPATCH_BLOCK_EVENT)) {
  276. Mage::dispatchEvent(
  277. 'controller_action_layout_generate_xml_before',
  278. array('action'=>$this, 'layout'=>$this->getLayout())
  279. );
  280. }
  281. // generate xml from collected text updates
  282. Varien_Profiler::start("$_profilerKey::layout_generate_xml");
  283. $this->getLayout()->generateXml();
  284. Varien_Profiler::stop("$_profilerKey::layout_generate_xml");
  285. return $this;
  286. }
  287. public function generateLayoutBlocks()
  288. {
  289. $_profilerKey = self::PROFILER_KEY . '::' . $this->getFullActionName();
  290. // dispatch event for adding xml layout elements
  291. if(!$this->getFlag('', self::FLAG_NO_DISPATCH_BLOCK_EVENT)) {
  292. Mage::dispatchEvent(
  293. 'controller_action_layout_generate_blocks_before',
  294. array('action'=>$this, 'layout'=>$this->getLayout())
  295. );
  296. }
  297. // generate blocks from xml layout
  298. Varien_Profiler::start("$_profilerKey::layout_generate_blocks");
  299. $this->getLayout()->generateBlocks();
  300. Varien_Profiler::stop("$_profilerKey::layout_generate_blocks");
  301. if(!$this->getFlag('', self::FLAG_NO_DISPATCH_BLOCK_EVENT)) {
  302. Mage::dispatchEvent(
  303. 'controller_action_layout_generate_blocks_after',
  304. array('action'=>$this, 'layout'=>$this->getLayout())
  305. );
  306. }
  307. return $this;
  308. }
  309. /**
  310. * Rendering layout
  311. *
  312. * @param string $output
  313. * @return Mage_Core_Controller_Varien_Action
  314. */
  315. public function renderLayout($output='')
  316. {
  317. $_profilerKey = self::PROFILER_KEY . '::' . $this->getFullActionName();
  318. if ($this->getFlag('', 'no-renderLayout')) {
  319. return;
  320. }
  321. if (Mage::app()->getFrontController()->getNoRender()) {
  322. return;
  323. }
  324. $this->_renderTitles();
  325. Varien_Profiler::start("$_profilerKey::layout_render");
  326. if (''!==$output) {
  327. $this->getLayout()->addOutputBlock($output);
  328. }
  329. Mage::dispatchEvent('controller_action_layout_render_before');
  330. Mage::dispatchEvent('controller_action_layout_render_before_'.$this->getFullActionName());
  331. #ob_implicit_flush();
  332. $this->getLayout()->setDirectOutput(false);
  333. $output = $this->getLayout()->getOutput();
  334. Mage::getSingleton('core/translate_inline')->processResponseBody($output);
  335. $this->getResponse()->appendBody($output);
  336. Varien_Profiler::stop("$_profilerKey::layout_render");
  337. return $this;
  338. }
  339. public function dispatch($action)
  340. {
  341. try {
  342. $actionMethodName = $this->getActionMethodName($action);
  343. if (!is_callable(array($this, $actionMethodName))) {
  344. $actionMethodName = 'norouteAction';
  345. }
  346. Varien_Profiler::start(self::PROFILER_KEY.'::predispatch');
  347. $this->preDispatch();
  348. Varien_Profiler::stop(self::PROFILER_KEY.'::predispatch');
  349. if ($this->getRequest()->isDispatched()) {
  350. /**
  351. * preDispatch() didn't change the action, so we can continue
  352. */
  353. if (!$this->getFlag('', self::FLAG_NO_DISPATCH)) {
  354. $_profilerKey = self::PROFILER_KEY.'::'.$this->getFullActionName();
  355. Varien_Profiler::start($_profilerKey);
  356. $this->$actionMethodName();
  357. Varien_Profiler::stop($_profilerKey);
  358. Varien_Profiler::start(self::PROFILER_KEY.'::postdispatch');
  359. $this->postDispatch();
  360. Varien_Profiler::stop(self::PROFILER_KEY.'::postdispatch');
  361. }
  362. }
  363. }
  364. catch (Mage_Core_Controller_Varien_Exception $e) {
  365. // set prepared flags
  366. foreach ($e->getResultFlags() as $flagData) {
  367. list($action, $flag, $value) = $flagData;
  368. $this->setFlag($action, $flag, $value);
  369. }
  370. // call forward, redirect or an action
  371. list($method, $parameters) = $e->getResultCallback();
  372. switch ($method) {
  373. case Mage_Core_Controller_Varien_Exception::RESULT_REDIRECT:
  374. list($path, $arguments) = $parameters;
  375. $this->_redirect($path, $arguments);
  376. break;
  377. case Mage_Core_Controller_Varien_Exception::RESULT_FORWARD:
  378. list($action, $controller, $module, $params) = $parameters;
  379. $this->_forward($action, $controller, $module, $params);
  380. break;
  381. default:
  382. $actionMethodName = $this->getActionMethodName($method);
  383. $this->getRequest()->setActionName($method);
  384. $this->$actionMethodName($method);
  385. break;
  386. }
  387. }
  388. }
  389. public function getActionMethodName($action)
  390. {
  391. $method = $action.'Action';
  392. return $method;
  393. }
  394. /**
  395. * Dispatches event before action
  396. */
  397. public function preDispatch()
  398. {
  399. if (!$this->getFlag('', self::FLAG_NO_CHECK_INSTALLATION)) {
  400. if (!Mage::isInstalled()) {
  401. $this->setFlag('', self::FLAG_NO_DISPATCH, true);
  402. $this->_redirect('install');
  403. return;
  404. }
  405. }
  406. // Prohibit disabled store actions
  407. if (Mage::isInstalled() && !Mage::app()->getStore()->getIsActive()) {
  408. Mage::app()->throwStoreException();
  409. }
  410. if ($this->_rewrite()) {
  411. return;
  412. }
  413. if (!$this->getFlag('', self::FLAG_NO_START_SESSION)) {
  414. $checkCookie = in_array($this->getRequest()->getActionName(), $this->_cookieCheckActions);
  415. $checkCookie = $checkCookie && !$this->getRequest()->getParam('nocookie', false);
  416. $cookies = Mage::getSingleton('core/cookie')->get();
  417. if ($checkCookie && empty($cookies)) {
  418. $this->setFlag('', self::FLAG_NO_COOKIES_REDIRECT, true);
  419. }
  420. Mage::getSingleton('core/session', array('name' => $this->_sessionNamespace))->start();
  421. }
  422. Mage::app()->loadArea($this->getLayout()->getArea());
  423. if ($this->getFlag('', self::FLAG_NO_COOKIES_REDIRECT)
  424. && Mage::getStoreConfig('web/browser_capabilities/cookies')) {
  425. $this->_forward('noCookies', 'index', 'core');
  426. return;
  427. }
  428. if ($this->getFlag('', self::FLAG_NO_PRE_DISPATCH)) {
  429. return;
  430. }
  431. Mage::dispatchEvent('controller_action_predispatch', array('controller_action'=>$this));
  432. Mage::dispatchEvent(
  433. 'controller_action_predispatch_'.$this->getRequest()->getRouteName(),
  434. array('controller_action'=>$this)
  435. );
  436. Varien_Autoload::registerScope($this->getRequest()->getRouteName());
  437. Mage::dispatchEvent(
  438. 'controller_action_predispatch_'.$this->getFullActionName(),
  439. array('controller_action'=>$this)
  440. );
  441. }
  442. /**
  443. * Dispatches event after action
  444. */
  445. public function postDispatch()
  446. {
  447. if ($this->getFlag('', self::FLAG_NO_POST_DISPATCH)) {
  448. return;
  449. }
  450. Mage::dispatchEvent(
  451. 'controller_action_postdispatch_'.$this->getFullActionName(),
  452. array('controller_action'=>$this)
  453. );
  454. Mage::dispatchEvent(
  455. 'controller_action_postdispatch_'.$this->getRequest()->getRouteName(),
  456. array('controller_action'=>$this)
  457. );
  458. Mage::dispatchEvent('controller_action_postdispatch', array('controller_action'=>$this));
  459. }
  460. public function norouteAction($coreRoute = null)
  461. {
  462. $status = ( $this->getRequest()->getParam('__status__') )
  463. ? $this->getRequest()->getParam('__status__')
  464. : new Varien_Object();
  465. Mage::dispatchEvent('controller_action_noroute', array('action'=>$this, 'status'=>$status));
  466. if ($status->getLoaded() !== true
  467. || $status->getForwarded() === true
  468. || !is_null($coreRoute) ) {
  469. $this->loadLayout(array('default', 'noRoute'));
  470. $this->renderLayout();
  471. } else {
  472. $status->setForwarded(true);
  473. #$this->_forward('cmsNoRoute', 'index', 'cms');
  474. $this->_forward(
  475. $status->getForwardAction(),
  476. $status->getForwardController(),
  477. $status->getForwardModule(),
  478. array('__status__' => $status));
  479. }
  480. }
  481. public function noCookiesAction()
  482. {
  483. $redirect = new Varien_Object();
  484. Mage::dispatchEvent('controller_action_nocookies', array(
  485. 'action' => $this,
  486. 'redirect' => $redirect
  487. ));
  488. if ($url = $redirect->getRedirectUrl()) {
  489. $this->_redirectUrl($url);
  490. }
  491. elseif ($redirect->getRedirect()) {
  492. $this->_redirect($redirect->getPath(), $redirect->getArguments());
  493. }
  494. else {
  495. $this->loadLayout(array('default', 'noCookie'));
  496. $this->renderLayout();
  497. }
  498. $this->getRequest()->setDispatched(true);
  499. }
  500. /**
  501. * Throw control to different action (control and module if was specified).
  502. *
  503. * @param string $action
  504. * @param string|null $controller
  505. * @param string|null $module
  506. * @param string|null $params
  507. */
  508. protected function _forward($action, $controller = null, $module = null, array $params = null)
  509. {
  510. $request = $this->getRequest();
  511. $request->initForward();
  512. if (!is_null($params)) {
  513. $request->setParams($params);
  514. }
  515. if (!is_null($controller)) {
  516. $request->setControllerName($controller);
  517. // Module should only be reset if controller has been specified
  518. if (!is_null($module)) {
  519. $request->setModuleName($module);
  520. }
  521. }
  522. $request->setActionName($action)
  523. ->setDispatched(false);
  524. }
  525. /**
  526. * Inits layout messages by message storage(s), loading and adding messages to layout messages block
  527. *
  528. * @param string|array $messagesStorage
  529. * @return Mage_Core_Controller_Varien_Action
  530. */
  531. protected function _initLayoutMessages($messagesStorage)
  532. {
  533. if (!is_array($messagesStorage)) {
  534. $messagesStorage = array($messagesStorage);
  535. }
  536. foreach ($messagesStorage as $storageName) {
  537. $storage = Mage::getSingleton($storageName);
  538. if ($storage) {
  539. $block = $this->getLayout()->getMessagesBlock();
  540. $block->addMessages($storage->getMessages(true));
  541. $block->setEscapeMessageFlag($storage->getEscapeMessages(true));
  542. }
  543. else {
  544. Mage::throwException(
  545. Mage::helper('core')->__('Invalid messages storage "%s" for layout messages initialization', (string) $storageName)
  546. );
  547. }
  548. }
  549. return $this;
  550. }
  551. /**
  552. * Inits layout messages by message storage(s), loading and adding messages to layout messages block
  553. *
  554. * @param string|array $messagesStorage
  555. * @return Mage_Core_Controller_Varien_Action
  556. */
  557. public function initLayoutMessages($messagesStorage)
  558. {
  559. return $this->_initLayoutMessages($messagesStorage);
  560. }
  561. /**
  562. * Set redirect url into response
  563. *
  564. * @param string $url
  565. * @return Mage_Core_Controller_Varien_Action
  566. */
  567. protected function _redirectUrl($url)
  568. {
  569. $this->getResponse()->setRedirect($url);
  570. return $this;
  571. }
  572. /**
  573. * Set redirect into response
  574. *
  575. * @param string $path
  576. * @param array $arguments
  577. */
  578. protected function _redirect($path, $arguments=array())
  579. {
  580. $this->getResponse()->setRedirect(Mage::getUrl($path, $arguments));
  581. return $this;
  582. }
  583. /**
  584. * Redirect to success page
  585. *
  586. * @param string $defaultUrl
  587. */
  588. protected function _redirectSuccess($defaultUrl)
  589. {
  590. $successUrl = $this->getRequest()->getParam(self::PARAM_NAME_SUCCESS_URL);
  591. if (empty($successUrl)) {
  592. $successUrl = $defaultUrl;
  593. }
  594. if (!$this->_isUrlInternal($successUrl)) {
  595. $successUrl = Mage::app()->getStore()->getBaseUrl();
  596. }
  597. $this->getResponse()->setRedirect($successUrl);
  598. return $this;
  599. }
  600. /**
  601. * Redirect to error page
  602. *
  603. * @param string $defaultUrl
  604. */
  605. protected function _redirectError($defaultUrl)
  606. {
  607. $errorUrl = $this->getRequest()->getParam(self::PARAM_NAME_ERROR_URL);
  608. if (empty($errorUrl)) {
  609. $errorUrl = $defaultUrl;
  610. }
  611. if (!$this->_isUrlInternal($errorUrl)) {
  612. $errorUrl = Mage::app()->getStore()->getBaseUrl();
  613. }
  614. $this->getResponse()->setRedirect($errorUrl);
  615. return $this;
  616. }
  617. /**
  618. * Set referer url for redirect in responce
  619. *
  620. * @param string $defaultUrl
  621. * @return Mage_Core_Controller_Varien_Action
  622. */
  623. protected function _redirectReferer($defaultUrl=null)
  624. {
  625. $refererUrl = $this->_getRefererUrl();
  626. if (empty($refererUrl)) {
  627. $refererUrl = empty($defaultUrl) ? Mage::getBaseUrl() : $defaultUrl;
  628. }
  629. $this->getResponse()->setRedirect($refererUrl);
  630. return $this;
  631. }
  632. /**
  633. * Identify referer url via all accepted methods (HTTP_REFERER, regular or base64-encoded request param)
  634. *
  635. * @return string
  636. */
  637. protected function _getRefererUrl()
  638. {
  639. $refererUrl = $this->getRequest()->getServer('HTTP_REFERER');
  640. if ($url = $this->getRequest()->getParam(self::PARAM_NAME_REFERER_URL)) {
  641. $refererUrl = $url;
  642. }
  643. if ($url = $this->getRequest()->getParam(self::PARAM_NAME_BASE64_URL)) {
  644. $refererUrl = Mage::helper('core')->urlDecode($url);
  645. }
  646. if ($url = $this->getRequest()->getParam(self::PARAM_NAME_URL_ENCODED)) {
  647. $refererUrl = Mage::helper('core')->urlDecode($url);
  648. }
  649. if (!$this->_isUrlInternal($refererUrl)) {
  650. $refererUrl = Mage::app()->getStore()->getBaseUrl();
  651. }
  652. return $refererUrl;
  653. }
  654. /**
  655. * Check url to be used as internal
  656. *
  657. * @param string $url
  658. * @return bool
  659. */
  660. protected function _isUrlInternal($url)
  661. {
  662. if (strpos($url, 'http') !== false) {
  663. /**
  664. * Url must start from base secure or base unsecure url
  665. */
  666. if ((strpos($url, Mage::app()->getStore()->getBaseUrl()) === 0)
  667. || (strpos($url, Mage::app()->getStore()->getBaseUrl(Mage_Core_Model_Store::URL_TYPE_LINK, true)) === 0)
  668. ) {
  669. return true;
  670. }
  671. }
  672. return false;
  673. }
  674. /**
  675. * Get real module name (like 'Mage_Module')
  676. *
  677. * @return string
  678. */
  679. protected function _getRealModuleName()
  680. {
  681. if (empty($this->_realModuleName)) {
  682. $class = get_class($this);
  683. $this->_realModuleName = substr(
  684. $class,
  685. 0,
  686. strpos(strtolower($class), '_' . strtolower($this->getRequest()->getControllerName() . 'Controller'))
  687. );
  688. }
  689. return $this->_realModuleName;
  690. }
  691. /**
  692. * Support for controllers rewrites
  693. *
  694. * Example of configuration:
  695. * <global>
  696. * <routers>
  697. * <core_module>
  698. * <rewrite>
  699. * <core_controller>
  700. * <to>new_route/new_controller</to>
  701. * <override_actions>true</override_actions>
  702. * <actions>
  703. * <core_action><to>new_module/new_controller/new_action</core_action>
  704. * </actions>
  705. * <core_controller>
  706. * </rewrite>
  707. * </core_module>
  708. * </routers>
  709. * </global>
  710. *
  711. * This will override:
  712. * 1. core_module/core_controller/core_action to new_module/new_controller/new_action
  713. * 2. all other actions of core_module/core_controller to new_module/new_controller
  714. *
  715. * @return boolean true if rewrite happened
  716. */
  717. protected function _rewrite()
  718. {
  719. $route = $this->getRequest()->getRouteName();
  720. $controller = $this->getRequest()->getControllerName();
  721. $action = $this->getRequest()->getActionName();
  722. $rewrite = Mage::getConfig()->getNode('global/routers/'.$route.'/rewrite/'.$controller);
  723. if (!$rewrite) {
  724. return false;
  725. }
  726. if (!($rewrite->actions && $rewrite->actions->$action) || $rewrite->is('override_actions')) {
  727. $t = explode('/', (string)$rewrite->to);
  728. if (sizeof($t)!==2 || empty($t[0]) || empty($t[1])) {
  729. return false;
  730. }
  731. $t[2] = $action;
  732. } else {
  733. $t = explode('/', (string)$rewrite->actions->$action->to);
  734. if (sizeof($t)!==3 || empty($t[0]) || empty($t[1]) || empty($t[2])) {
  735. return false;
  736. }
  737. }
  738. $this->_forward(
  739. $t[2]==='*' ? $action : $t[2],
  740. $t[1]==='*' ? $controller : $t[1],
  741. $t[0]==='*' ? $route : $t[0]
  742. );
  743. return true;
  744. }
  745. /**
  746. * Validate Form Key
  747. *
  748. * @return bool
  749. */
  750. protected function _validateFormKey()
  751. {
  752. if (!($formKey = $this->getRequest()->getParam('form_key', null))
  753. || $formKey != Mage::getSingleton('core/session')->getFormKey()) {
  754. return false;
  755. }
  756. return true;
  757. }
  758. /**
  759. * Add an extra title to the end or one from the end, or remove all
  760. *
  761. * Usage examples:
  762. * $this->_title('foo')->_title('bar');
  763. * => bar / foo / <default title>
  764. *
  765. * $this->_title()->_title('foo')->_title('bar');
  766. * => bar / foo
  767. *
  768. * $this->_title('foo')->_title(false)->_title('bar');
  769. * bar / <default title>
  770. *
  771. * @see self::_renderTitles()
  772. * @param string|false|-1|null $text
  773. * @return Mage_Core_Controller_Varien_Action
  774. */
  775. protected function _title($text = null, $resetIfExists = true)
  776. {
  777. if (is_string($text)) {
  778. $this->_titles[] = $text;
  779. } elseif (-1 === $text) {
  780. if (empty($this->_titles)) {
  781. $this->_removeDefaultTitle = true;
  782. } else {
  783. array_pop($this->_titles);
  784. }
  785. } elseif (empty($this->_titles) || $resetIfExists) {
  786. if (false === $text) {
  787. $this->_removeDefaultTitle = false;
  788. $this->_titles = array();
  789. } elseif (null === $text) {
  790. $this->_removeDefaultTitle = true;
  791. $this->_titles = array();
  792. }
  793. }
  794. return $this;
  795. }
  796. /**
  797. * Prepare titles in the 'head' layout block
  798. * Supposed to work only in actions where layout is rendered
  799. * Falls back to the default logic if there are no titles eventually
  800. *
  801. * @see self::loadLayout()
  802. * @see self::renderLayout()
  803. */
  804. protected function _renderTitles()
  805. {
  806. if ($this->_isLayoutLoaded && $this->_titles) {
  807. $titleBlock = $this->getLayout()->getBlock('head');
  808. if ($titleBlock) {
  809. if (!$this->_removeDefaultTitle) {
  810. $title = trim($titleBlock->getTitle());
  811. if ($title) {
  812. array_unshift($this->_titles, $title);
  813. }
  814. }
  815. $titleBlock->setTitle(implode(' / ', array_reverse($this->_titles)));
  816. }
  817. }
  818. }
  819. /**
  820. * Convert dates in array from localized to internal format
  821. *
  822. * @param array $array
  823. * @param array $dateFields
  824. * @return array
  825. */
  826. protected function _filterDates($array, $dateFields)
  827. {
  828. if (empty($dateFields)) {
  829. return $array;
  830. }
  831. $filterInput = new Zend_Filter_LocalizedToNormalized(array(
  832. 'date_format' => Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT)
  833. ));
  834. $filterInternal = new Zend_Filter_NormalizedToLocalized(array(
  835. 'date_format' => Varien_Date::DATE_INTERNAL_FORMAT
  836. ));
  837. foreach ($dateFields as $dateField) {
  838. if (array_key_exists($dateField, $array) && !empty($dateField)) {
  839. $array[$dateField] = $filterInput->filter($array[$dateField]);
  840. $array[$dateField] = $filterInternal->filter($array[$dateField]);
  841. }
  842. }
  843. return $array;
  844. }
  845. /**
  846. * Convert dates with time in array from localized to internal format
  847. *
  848. * @param array $array
  849. * @param array $dateFields
  850. * @return array
  851. */
  852. protected function _filterDateTime($array, $dateFields)
  853. {
  854. if (empty($dateFields)) {
  855. return $array;
  856. }
  857. $filterInput = new Zend_Filter_LocalizedToNormalized(array(
  858. 'date_format' => Mage::app()->getLocale()->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT)
  859. ));
  860. $filterInternal = new Zend_Filter_NormalizedToLocalized(array(
  861. 'date_format' => Varien_Date::DATETIME_INTERNAL_FORMAT
  862. ));
  863. foreach ($dateFields as $dateField) {
  864. if (array_key_exists($dateField, $array) && !empty($dateField)) {
  865. $array[$dateField] = $filterInput->filter($array[$dateField]);
  866. $array[$dateField] = $filterInternal->filter($array[$dateField]);
  867. }
  868. }
  869. return $array;
  870. }
  871. /**
  872. * Declare headers and content file in responce for file download
  873. *
  874. * @param string $fileName
  875. * @param string|array $content set to null to avoid starting output, $contentLength should be set explicitly in
  876. * that case
  877. * @param string $contentType
  878. * @param int $contentLength explicit content length, if strlen($content) isn't applicable
  879. * @return Mage_Core_Controller_Varien_Action
  880. */
  881. protected function _prepareDownloadResponse(
  882. $fileName,
  883. $content,
  884. $contentType = 'application/octet-stream',
  885. $contentLength = null)
  886. {
  887. $session = Mage::getSingleton('admin/session');
  888. if ($session->isFirstPageAfterLogin()) {
  889. $this->_redirect($session->getUser()->getStartupPageUrl());
  890. return $this;
  891. }
  892. $isFile = false;
  893. $file = null;
  894. if (is_array($content)) {
  895. if (!isset($content['type']) || !isset($content['value'])) {
  896. return $this;
  897. }
  898. if ($content['type'] == 'filename') {
  899. $isFile = true;
  900. $file = $content['value'];
  901. $contentLength = filesize($file);
  902. }
  903. }
  904. $this->getResponse()
  905. ->setHttpResponseCode(200)
  906. ->setHeader('Pragma', 'public', true)
  907. ->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true)
  908. ->setHeader('Content-type', $contentType, true)
  909. ->setHeader('Content-Length', is_null($contentLength) ? strlen($content) : $contentLength)
  910. ->setHeader('Content-Disposition', 'attachment; filename="'.$fileName.'"')
  911. ->setHeader('Last-Modified', date('r'));
  912. if (!is_null($content)) {
  913. if ($isFile) {
  914. $this->getResponse()->clearBody();
  915. $this->getResponse()->sendHeaders();
  916. $ioAdapter = new Varien_Io_File();
  917. $ioAdapter->open(array('path' => $ioAdapter->dirname($file)));
  918. $ioAdapter->streamOpen($file, 'r');
  919. while ($buffer = $ioAdapter->streamRead()) {
  920. print $buffer;
  921. }
  922. $ioAdapter->streamClose();
  923. if (!empty($content['rm'])) {
  924. $ioAdapter->rm($file);
  925. }
  926. } else {
  927. $this->getResponse()->setBody($content);
  928. }
  929. }
  930. return $this;
  931. }
  932. }