AbstractAction.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Backend\App;
  7. /**
  8. * Generic backend controller
  9. *
  10. * @api
  11. * @SuppressWarnings(PHPMD.NumberOfChildren)
  12. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  13. * @since 100.0.2
  14. */
  15. abstract class AbstractAction extends \Magento\Framework\App\Action\Action
  16. {
  17. /**
  18. * Name of "is URLs checked" flag
  19. */
  20. const FLAG_IS_URLS_CHECKED = 'check_url_settings';
  21. /**
  22. * Session namespace to refer in other places
  23. */
  24. const SESSION_NAMESPACE = 'adminhtml';
  25. /**
  26. * Authorization level of a basic admin session
  27. */
  28. const ADMIN_RESOURCE = 'Magento_Backend::admin';
  29. /**
  30. * Array of actions which can be processed without secret key validation
  31. *
  32. * @var array
  33. */
  34. protected $_publicActions = [];
  35. /**
  36. * Namespace for session.
  37. *
  38. * @var string
  39. */
  40. protected $_sessionNamespace = self::SESSION_NAMESPACE;
  41. /**
  42. * @var \Magento\Backend\Helper\Data
  43. */
  44. protected $_helper;
  45. /**
  46. * @var \Magento\Backend\Model\Session
  47. */
  48. protected $_session;
  49. /**
  50. * @var \Magento\Framework\AuthorizationInterface
  51. */
  52. protected $_authorization;
  53. /**
  54. * @var \Magento\Backend\Model\Auth
  55. */
  56. protected $_auth;
  57. /**
  58. * @var \Magento\Backend\Model\UrlInterface
  59. */
  60. protected $_backendUrl;
  61. /**
  62. * @var \Magento\Framework\Locale\ResolverInterface
  63. */
  64. protected $_localeResolver;
  65. /**
  66. * @var bool
  67. */
  68. protected $_canUseBaseUrl;
  69. /**
  70. * @var \Magento\Framework\Data\Form\FormKey\Validator
  71. */
  72. protected $_formKeyValidator;
  73. /**
  74. * @param \Magento\Backend\App\Action\Context $context
  75. */
  76. public function __construct(Action\Context $context)
  77. {
  78. parent::__construct($context);
  79. $this->_authorization = $context->getAuthorization();
  80. $this->_auth = $context->getAuth();
  81. $this->_helper = $context->getHelper();
  82. $this->_backendUrl = $context->getBackendUrl();
  83. $this->_formKeyValidator = $context->getFormKeyValidator();
  84. $this->_localeResolver = $context->getLocaleResolver();
  85. $this->_canUseBaseUrl = $context->getCanUseBaseUrl();
  86. $this->_session = $context->getSession();
  87. }
  88. /**
  89. * @return bool
  90. */
  91. protected function _isAllowed()
  92. {
  93. return $this->_authorization->isAllowed(static::ADMIN_RESOURCE);
  94. }
  95. /**
  96. * Retrieve adminhtml session model object
  97. *
  98. * @return \Magento\Backend\Model\Session
  99. */
  100. protected function _getSession()
  101. {
  102. return $this->_session;
  103. }
  104. /**
  105. * @return \Magento\Framework\Message\ManagerInterface
  106. */
  107. protected function getMessageManager()
  108. {
  109. return $this->messageManager;
  110. }
  111. /**
  112. * Define active menu item in menu block
  113. *
  114. * @param string $itemId current active menu item
  115. * @return $this
  116. */
  117. protected function _setActiveMenu($itemId)
  118. {
  119. /** @var $menuBlock \Magento\Backend\Block\Menu */
  120. $menuBlock = $this->_view->getLayout()->getBlock('menu');
  121. $menuBlock->setActive($itemId);
  122. $parents = $menuBlock->getMenuModel()->getParentItems($itemId);
  123. foreach ($parents as $item) {
  124. /** @var $item \Magento\Backend\Model\Menu\Item */
  125. $this->_view->getPage()->getConfig()->getTitle()->prepend($item->getTitle());
  126. }
  127. return $this;
  128. }
  129. /**
  130. * @param string $label
  131. * @param string $title
  132. * @param string|null $link
  133. * @return $this
  134. */
  135. protected function _addBreadcrumb($label, $title, $link = null)
  136. {
  137. $this->_view->getLayout()->getBlock('breadcrumbs')->addLink($label, $title, $link);
  138. return $this;
  139. }
  140. /**
  141. * @param \Magento\Framework\View\Element\AbstractBlock $block
  142. * @return $this
  143. */
  144. protected function _addContent(\Magento\Framework\View\Element\AbstractBlock $block)
  145. {
  146. return $this->_moveBlockToContainer($block, 'content');
  147. }
  148. /**
  149. * @param \Magento\Framework\View\Element\AbstractBlock $block
  150. * @return $this
  151. */
  152. protected function _addLeft(\Magento\Framework\View\Element\AbstractBlock $block)
  153. {
  154. return $this->_moveBlockToContainer($block, 'left');
  155. }
  156. /**
  157. * @param \Magento\Framework\View\Element\AbstractBlock $block
  158. * @return $this
  159. */
  160. protected function _addJs(\Magento\Framework\View\Element\AbstractBlock $block)
  161. {
  162. return $this->_moveBlockToContainer($block, 'js');
  163. }
  164. /**
  165. * Set specified block as an anonymous child to specified container
  166. *
  167. * The block will be moved to the container from previous parent after all other elements
  168. *
  169. * @param \Magento\Framework\View\Element\AbstractBlock $block
  170. * @param string $containerName
  171. * @return $this
  172. */
  173. private function _moveBlockToContainer(\Magento\Framework\View\Element\AbstractBlock $block, $containerName)
  174. {
  175. $this->_view->getLayout()->setChild($containerName, $block->getNameInLayout(), '');
  176. return $this;
  177. }
  178. /**
  179. * @param \Magento\Framework\App\RequestInterface $request
  180. * @return \Magento\Framework\App\ResponseInterface
  181. */
  182. public function dispatch(\Magento\Framework\App\RequestInterface $request)
  183. {
  184. if ($request->isDispatched() && $request->getActionName() !== 'denied' && !$this->_isAllowed()) {
  185. $this->_response->setStatusHeader(403, '1.1', 'Forbidden');
  186. if (!$this->_auth->isLoggedIn()) {
  187. return $this->_redirect('*/auth/login');
  188. }
  189. $this->_view->loadLayout(['default', 'adminhtml_denied'], true, true, false);
  190. $this->_view->renderLayout();
  191. $this->_request->setDispatched(true);
  192. return $this->_response;
  193. }
  194. if ($this->_isUrlChecked()) {
  195. $this->_actionFlag->set('', self::FLAG_IS_URLS_CHECKED, true);
  196. }
  197. $this->_processLocaleSettings();
  198. // Need to preload isFirstPageAfterLogin (see https://github.com/magento/magento2/issues/15510)
  199. if ($this->_auth->isLoggedIn()) {
  200. $this->_auth->getAuthStorage()->isFirstPageAfterLogin();
  201. }
  202. return parent::dispatch($request);
  203. }
  204. /**
  205. * Check whether url is checked
  206. *
  207. * @return bool
  208. */
  209. protected function _isUrlChecked()
  210. {
  211. return !$this->_actionFlag->get('', self::FLAG_IS_URLS_CHECKED)
  212. && !$this->getRequest()->isForwarded()
  213. && !$this->_getSession()->getIsUrlNotice(true)
  214. && !$this->_canUseBaseUrl;
  215. }
  216. /**
  217. * Check url keys. If non valid - redirect
  218. *
  219. * @return bool
  220. *
  221. * @see \Magento\Backend\App\Request\BackendValidator for default
  222. * request validation.
  223. */
  224. public function _processUrlKeys()
  225. {
  226. $_isValidFormKey = true;
  227. $_isValidSecretKey = true;
  228. $_keyErrorMsg = '';
  229. if ($this->_auth->isLoggedIn()) {
  230. if ($this->getRequest()->isPost()) {
  231. $_isValidFormKey = $this->_formKeyValidator->validate($this->getRequest());
  232. $_keyErrorMsg = __('Invalid Form Key. Please refresh the page.');
  233. } elseif ($this->_backendUrl->useSecretKey()) {
  234. $_isValidSecretKey = $this->_validateSecretKey();
  235. $_keyErrorMsg = __('You entered an invalid Secret Key. Please refresh the page.');
  236. }
  237. }
  238. if (!$_isValidFormKey || !$_isValidSecretKey) {
  239. $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true);
  240. $this->_actionFlag->set('', self::FLAG_NO_POST_DISPATCH, true);
  241. if ($this->getRequest()->getQuery('isAjax', false) || $this->getRequest()->getQuery('ajax', false)) {
  242. $this->getResponse()->representJson(
  243. $this->_objectManager->get(
  244. \Magento\Framework\Json\Helper\Data::class
  245. )->jsonEncode(
  246. ['error' => true, 'message' => $_keyErrorMsg]
  247. )
  248. );
  249. } else {
  250. $this->_redirect($this->_backendUrl->getStartupPageUrl());
  251. }
  252. return false;
  253. }
  254. return true;
  255. }
  256. /**
  257. * Set session locale,
  258. * process force locale set through url params
  259. *
  260. * @return $this
  261. */
  262. protected function _processLocaleSettings()
  263. {
  264. $forceLocale = $this->getRequest()->getParam('locale', null);
  265. if ($this->_objectManager->get(\Magento\Framework\Validator\Locale::class)->isValid($forceLocale)) {
  266. $this->_getSession()->setSessionLocale($forceLocale);
  267. }
  268. if ($this->_getSession()->getLocale() === null) {
  269. $this->_getSession()->setLocale($this->_localeResolver->getLocale());
  270. }
  271. return $this;
  272. }
  273. /**
  274. * Set redirect into response
  275. *
  276. * @TODO MAGETWO-28356: Refactor controller actions to new ResultInterface
  277. * @param string $path
  278. * @param array $arguments
  279. * @return \Magento\Framework\App\ResponseInterface
  280. */
  281. protected function _redirect($path, $arguments = [])
  282. {
  283. $this->_getSession()->setIsUrlNotice($this->_actionFlag->get('', self::FLAG_IS_URLS_CHECKED));
  284. $this->getResponse()->setRedirect($this->getUrl($path, $arguments));
  285. return $this->getResponse();
  286. }
  287. /**
  288. * Forward to action
  289. *
  290. * @TODO MAGETWO-28356: Refactor controller actions to new ResultInterface
  291. * @param string $action
  292. * @param string|null $controller
  293. * @param string|null $module
  294. * @param array|null $params
  295. * @return void
  296. */
  297. protected function _forward($action, $controller = null, $module = null, array $params = null)
  298. {
  299. $this->_getSession()->setIsUrlNotice($this->_actionFlag->get('', self::FLAG_IS_URLS_CHECKED));
  300. return parent::_forward($action, $controller, $module, $params);
  301. }
  302. /**
  303. * Generate url by route and parameters
  304. *
  305. * @param string $route
  306. * @param array $params
  307. * @return string
  308. */
  309. public function getUrl($route = '', $params = [])
  310. {
  311. return $this->_helper->getUrl($route, $params);
  312. }
  313. /**
  314. * Validate Secret Key
  315. *
  316. * @return bool
  317. */
  318. protected function _validateSecretKey()
  319. {
  320. if (is_array($this->_publicActions) && in_array($this->getRequest()->getActionName(), $this->_publicActions)) {
  321. return true;
  322. }
  323. $secretKey = $this->getRequest()->getParam(\Magento\Backend\Model\UrlInterface::SECRET_KEY_PARAM_NAME, null);
  324. if (!$secretKey || $secretKey != $this->_backendUrl->getSecretKey()) {
  325. return false;
  326. }
  327. return true;
  328. }
  329. }