Tabs.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Backend\Block\Widget;
  7. use Magento\Backend\Block\Widget\Tab\TabInterface;
  8. /**
  9. * Tabs widget
  10. *
  11. * @api
  12. * @SuppressWarnings(PHPMD.NumberOfChildren)
  13. * @since 100.0.2
  14. */
  15. class Tabs extends \Magento\Backend\Block\Widget
  16. {
  17. /**
  18. * Tabs structure
  19. *
  20. * @var array
  21. */
  22. protected $_tabs = [];
  23. /**
  24. * Active tab key
  25. *
  26. * @var string
  27. */
  28. protected $_activeTab = null;
  29. /**
  30. * Destination HTML element id
  31. *
  32. * @var string
  33. */
  34. protected $_destElementId = 'content';
  35. /**
  36. * @var string
  37. */
  38. protected $_template = 'Magento_Backend::widget/tabs.phtml';
  39. /**
  40. * @var \Magento\Backend\Model\Auth\Session
  41. */
  42. protected $_authSession;
  43. /**
  44. * @var \Magento\Framework\Json\EncoderInterface
  45. */
  46. private $_jsonEncoder;
  47. /**
  48. * @param \Magento\Backend\Block\Template\Context $context
  49. * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
  50. * @param \Magento\Backend\Model\Auth\Session $authSession
  51. * @param array $data
  52. */
  53. public function __construct(
  54. \Magento\Backend\Block\Template\Context $context,
  55. \Magento\Framework\Json\EncoderInterface $jsonEncoder,
  56. \Magento\Backend\Model\Auth\Session $authSession,
  57. array $data = []
  58. ) {
  59. $this->_authSession = $authSession;
  60. parent::__construct($context, $data);
  61. $this->_jsonEncoder = $jsonEncoder;
  62. }
  63. /**
  64. * Retrieve destination html element id
  65. *
  66. * @return string
  67. */
  68. public function getDestElementId()
  69. {
  70. return $this->_destElementId;
  71. }
  72. /**
  73. * Set destination element id
  74. *
  75. * @param string $elementId
  76. * @return $this
  77. */
  78. public function setDestElementId($elementId)
  79. {
  80. $this->_destElementId = $elementId;
  81. return $this;
  82. }
  83. /**
  84. * Add new tab after another
  85. *
  86. * @param string $tabId new tab Id
  87. * @param array|\Magento\Framework\DataObject $tab
  88. * @param string $afterTabId
  89. * @return void
  90. */
  91. public function addTabAfter($tabId, $tab, $afterTabId)
  92. {
  93. $this->addTab($tabId, $tab);
  94. $this->_tabs[$tabId]->setAfter($afterTabId);
  95. }
  96. /**
  97. * Add new tab
  98. *
  99. * @param string $tabId
  100. * @param array|\Magento\Framework\DataObject|string $tab
  101. * @return $this
  102. * @throws \Exception
  103. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  104. */
  105. public function addTab($tabId, $tab)
  106. {
  107. if (empty($tabId)) {
  108. throw new \Exception(__('Please correct the tab configuration and try again. Tab Id should be not empty'));
  109. }
  110. if (is_array($tab)) {
  111. $this->_tabs[$tabId] = new \Magento\Framework\DataObject($tab);
  112. } elseif ($tab instanceof \Magento\Framework\DataObject) {
  113. $this->_tabs[$tabId] = $tab;
  114. if (!$this->_tabs[$tabId]->hasTabId()) {
  115. $this->_tabs[$tabId]->setTabId($tabId);
  116. }
  117. } elseif (is_string($tab)) {
  118. $this->_addTabByName($tab, $tabId);
  119. if (!$this->_tabs[$tabId] instanceof TabInterface) {
  120. unset($this->_tabs[$tabId]);
  121. return $this;
  122. }
  123. } else {
  124. throw new \Exception(__('Please correct the tab configuration and try again.'));
  125. }
  126. if ($this->_tabs[$tabId]->getUrl() === null) {
  127. $this->_tabs[$tabId]->setUrl('#');
  128. }
  129. if (!$this->_tabs[$tabId]->getTitle()) {
  130. $this->_tabs[$tabId]->setTitle($this->_tabs[$tabId]->getLabel());
  131. }
  132. $this->_tabs[$tabId]->setId($tabId);
  133. $this->_tabs[$tabId]->setTabId($tabId);
  134. if (true === $this->_tabs[$tabId]->getActive()) {
  135. $this->setActiveTab($tabId);
  136. }
  137. return $this;
  138. }
  139. /**
  140. * Add tab by tab block name
  141. *
  142. * @param string $tab
  143. * @param string $tabId
  144. * @return void
  145. * @throws \Exception
  146. */
  147. protected function _addTabByName($tab, $tabId)
  148. {
  149. if (strpos($tab, '\Block\\') !== false) {
  150. $this->_tabs[$tabId] = $this->getLayout()->createBlock($tab, $this->getNameInLayout() . '_tab_' . $tabId);
  151. } elseif ($this->getChildBlock($tab)) {
  152. $this->_tabs[$tabId] = $this->getChildBlock($tab);
  153. } else {
  154. $this->_tabs[$tabId] = null;
  155. }
  156. if ($this->_tabs[$tabId] !== null && !$this->_tabs[$tabId] instanceof TabInterface) {
  157. throw new \Exception(__('Please correct the tab configuration and try again.'));
  158. }
  159. }
  160. /**
  161. * Get active tab id
  162. *
  163. * @return string
  164. */
  165. public function getActiveTabId()
  166. {
  167. return $this->getTabId($this->_tabs[$this->_activeTab]);
  168. }
  169. /**
  170. * Set Active Tab
  171. *
  172. * Tab has to be not hidden and can show
  173. *
  174. * @param string $tabId
  175. * @return $this
  176. */
  177. public function setActiveTab($tabId)
  178. {
  179. if (isset(
  180. $this->_tabs[$tabId]
  181. ) && $this->canShowTab(
  182. $this->_tabs[$tabId]
  183. ) && !$this->getTabIsHidden(
  184. $this->_tabs[$tabId]
  185. )
  186. ) {
  187. $this->_activeTab = $tabId;
  188. if ($this->_activeTab !== null && $tabId !== $this->_activeTab) {
  189. foreach ($this->_tabs as $id => $tab) {
  190. $tab->setActive($id === $tabId);
  191. }
  192. }
  193. }
  194. return $this;
  195. }
  196. /**
  197. * Set Active Tab
  198. *
  199. * @param string $tabId
  200. * @return $this
  201. */
  202. protected function _setActiveTab($tabId)
  203. {
  204. foreach ($this->_tabs as $id => $tab) {
  205. if ($this->getTabId($tab) == $tabId) {
  206. $this->_activeTab = $id;
  207. $tab->setActive(true);
  208. return $this;
  209. }
  210. }
  211. return $this;
  212. }
  213. /**
  214. * @inheritdoc
  215. */
  216. protected function _beforeToHtml()
  217. {
  218. $this->_tabs = $this->reorderTabs();
  219. if ($activeTab = $this->getRequest()->getParam('active_tab')) {
  220. $this->setActiveTab($activeTab);
  221. } elseif ($activeTabId = $this->_authSession->getActiveTabId()) {
  222. $this->_setActiveTab($activeTabId);
  223. }
  224. if ($this->_activeTab === null && !empty($this->_tabs)) {
  225. /** @var TabInterface $tab */
  226. $this->_activeTab = (reset($this->_tabs))->getId();
  227. }
  228. $this->assign('tabs', $this->_tabs);
  229. return parent::_beforeToHtml();
  230. }
  231. /**
  232. * Reorder the tabs.
  233. *
  234. * @return array
  235. */
  236. private function reorderTabs()
  237. {
  238. $orderByIdentity = [];
  239. $orderByPosition = [];
  240. $position = 100;
  241. /**
  242. * Set the initial positions for each tab.
  243. *
  244. * @var string $key
  245. * @var TabInterface $tab
  246. */
  247. foreach ($this->_tabs as $key => $tab) {
  248. $tab->setPosition($position);
  249. $orderByIdentity[$key] = $tab;
  250. $orderByPosition[$position] = $tab;
  251. $position += 100;
  252. }
  253. return $this->applyTabsCorrectOrder($orderByPosition, $orderByIdentity);
  254. }
  255. /**
  256. * Apply tabs order
  257. *
  258. * @param array $orderByPosition
  259. * @param array $orderByIdentity
  260. *
  261. * @return array
  262. */
  263. private function applyTabsCorrectOrder(array $orderByPosition, array $orderByIdentity)
  264. {
  265. $positionFactor = 1;
  266. /**
  267. * Rearrange the positions by using the after tag for each tab.
  268. *
  269. * @var int $position
  270. * @var TabInterface $tab
  271. */
  272. foreach ($orderByPosition as $position => $tab) {
  273. if (!$tab->getAfter() || !in_array($tab->getAfter(), array_keys($orderByIdentity))) {
  274. $positionFactor = 1;
  275. continue;
  276. }
  277. $grandPosition = $orderByIdentity[$tab->getAfter()]->getPosition();
  278. $newPosition = $grandPosition + $positionFactor;
  279. unset($orderByPosition[$position]);
  280. $orderByPosition[$newPosition] = $tab;
  281. $tab->setPosition($newPosition);
  282. $positionFactor++;
  283. }
  284. return $this->finalTabsSortOrder($orderByPosition);
  285. }
  286. /**
  287. * Apply the last sort order to tabs.
  288. *
  289. * @param array $orderByPosition
  290. *
  291. * @return array
  292. */
  293. private function finalTabsSortOrder(array $orderByPosition)
  294. {
  295. ksort($orderByPosition);
  296. $ordered = [];
  297. /** @var TabInterface $tab */
  298. foreach ($orderByPosition as $tab) {
  299. $ordered[$tab->getId()] = $tab;
  300. }
  301. return $ordered;
  302. }
  303. /**
  304. * Get js object name
  305. *
  306. * @return string
  307. */
  308. public function getJsObjectName()
  309. {
  310. return $this->getId() . 'JsTabs';
  311. }
  312. /**
  313. * Get tabs ids
  314. *
  315. * @return string[]
  316. */
  317. public function getTabsIds()
  318. {
  319. if (empty($this->_tabs)) {
  320. return [];
  321. }
  322. return array_keys($this->_tabs);
  323. }
  324. /**
  325. * Get tab id
  326. *
  327. * @param \Magento\Framework\DataObject|TabInterface $tab
  328. * @param bool $withPrefix
  329. * @return string
  330. */
  331. public function getTabId($tab, $withPrefix = true)
  332. {
  333. if ($tab instanceof TabInterface) {
  334. return ($withPrefix ? $this->getId() . '_' : '') . $tab->getTabId();
  335. }
  336. return ($withPrefix ? $this->getId() . '_' : '') . $tab->getId();
  337. }
  338. /**
  339. * CVan show tab
  340. *
  341. * @param \Magento\Framework\DataObject|TabInterface $tab
  342. * @return bool
  343. */
  344. public function canShowTab($tab)
  345. {
  346. if ($tab instanceof TabInterface) {
  347. return $tab->canShowTab();
  348. }
  349. return true;
  350. }
  351. /**
  352. * Get tab is hidden
  353. *
  354. * @param \Magento\Framework\DataObject|TabInterface $tab
  355. * @return bool
  356. * @SuppressWarnings(PHPMD.BooleanGetMethodName)
  357. */
  358. public function getTabIsHidden($tab)
  359. {
  360. if ($tab instanceof TabInterface) {
  361. return $tab->isHidden();
  362. }
  363. return $tab->getIsHidden();
  364. }
  365. /**
  366. * Get tab url
  367. *
  368. * @param \Magento\Framework\DataObject|TabInterface $tab
  369. * @return string
  370. */
  371. public function getTabUrl($tab)
  372. {
  373. if ($tab instanceof TabInterface) {
  374. if (method_exists($tab, 'getTabUrl')) {
  375. return $tab->getTabUrl();
  376. }
  377. return '#';
  378. }
  379. if ($tab->getUrl() !== null) {
  380. return $tab->getUrl();
  381. }
  382. return '#';
  383. }
  384. /**
  385. * Get tab title
  386. *
  387. * @param \Magento\Framework\DataObject|TabInterface $tab
  388. * @return string
  389. */
  390. public function getTabTitle($tab)
  391. {
  392. if ($tab instanceof TabInterface) {
  393. return $tab->getTabTitle();
  394. }
  395. return $tab->getTitle();
  396. }
  397. /**
  398. * Get tab class
  399. *
  400. * @param \Magento\Framework\DataObject|TabInterface $tab
  401. * @return string
  402. */
  403. public function getTabClass($tab)
  404. {
  405. if ($tab instanceof TabInterface) {
  406. if (method_exists($tab, 'getTabClass')) {
  407. return $tab->getTabClass();
  408. }
  409. return '';
  410. }
  411. return $tab->getClass();
  412. }
  413. /**
  414. * Get tab label
  415. *
  416. * @param \Magento\Framework\DataObject|TabInterface $tab
  417. * @return string
  418. */
  419. public function getTabLabel($tab)
  420. {
  421. if ($tab instanceof TabInterface) {
  422. return $tab->getTabLabel();
  423. }
  424. return $tab->getLabel();
  425. }
  426. /**
  427. * Get tab content
  428. *
  429. * @param \Magento\Framework\DataObject|TabInterface $tab
  430. * @return string
  431. */
  432. public function getTabContent($tab)
  433. {
  434. if ($tab instanceof TabInterface) {
  435. if ($tab->getSkipGenerateContent()) {
  436. return '';
  437. }
  438. return $tab->toHtml();
  439. }
  440. return $tab->getContent();
  441. }
  442. /**
  443. * Mark tabs as dependent of each other
  444. *
  445. * Arbitrary number of tabs can be specified, but at least two
  446. *
  447. * @param string $tabOneId
  448. * @param string $tabTwoId
  449. * @return void
  450. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  451. */
  452. public function bindShadowTabs($tabOneId, $tabTwoId)
  453. {
  454. $tabs = [];
  455. $args = func_get_args();
  456. if (!empty($args) && count($args) > 1) {
  457. foreach ($args as $tabId) {
  458. if (isset($this->_tabs[$tabId])) {
  459. $tabs[$tabId] = $tabId;
  460. }
  461. }
  462. $blockId = $this->getId();
  463. foreach ($tabs as $tabId) {
  464. foreach ($tabs as $tabToId) {
  465. if ($tabId !== $tabToId) {
  466. if (!$this->_tabs[$tabToId]->getData('shadow_tabs')) {
  467. $this->_tabs[$tabToId]->setData('shadow_tabs', []);
  468. }
  469. $this->_tabs[$tabToId]->setData(
  470. 'shadow_tabs',
  471. array_merge($this->_tabs[$tabToId]->getData('shadow_tabs'), [$blockId . '_' . $tabId])
  472. );
  473. }
  474. }
  475. }
  476. }
  477. }
  478. /**
  479. * Obtain shadow tabs information
  480. *
  481. * @param bool $asJson
  482. * @return array|string
  483. */
  484. public function getAllShadowTabs($asJson = true)
  485. {
  486. $result = [];
  487. if (!empty($this->_tabs)) {
  488. $blockId = $this->getId();
  489. foreach (array_keys($this->_tabs) as $tabId) {
  490. if ($this->_tabs[$tabId]->getData('shadow_tabs')) {
  491. $result[$blockId . '_' . $tabId] = $this->_tabs[$tabId]->getData('shadow_tabs');
  492. }
  493. }
  494. }
  495. if ($asJson) {
  496. return $this->_jsonEncoder->encode($result);
  497. }
  498. return $result;
  499. }
  500. /**
  501. * Set tab property by tab's identifier
  502. *
  503. * @param string $tab
  504. * @param string $key
  505. * @param mixed $value
  506. * @return $this
  507. */
  508. public function setTabData($tab, $key, $value)
  509. {
  510. if (isset($this->_tabs[$tab]) && $this->_tabs[$tab] instanceof \Magento\Framework\DataObject) {
  511. if ($key == 'url') {
  512. $value = $this->getUrl($value, ['_current' => true, '_use_rewrite' => true]);
  513. }
  514. $this->_tabs[$tab]->setData($key, $value);
  515. }
  516. return $this;
  517. }
  518. /**
  519. * Removes tab with passed id from tabs block
  520. *
  521. * @param string $tabId
  522. * @return $this
  523. */
  524. public function removeTab($tabId)
  525. {
  526. if (isset($this->_tabs[$tabId])) {
  527. unset($this->_tabs[$tabId]);
  528. }
  529. return $this;
  530. }
  531. }