BxDevModule.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup Developer Developer
  7. * @ingroup UnaModules
  8. *
  9. * @{
  10. */
  11. require_once('BxDevFunctions.php');
  12. define('BX_DEV_TOOLS_SETTINGS', 'settings');
  13. define('BX_DEV_TOOLS_FORMS', 'forms');
  14. define('BX_DEV_TOOLS_PAGES', 'pages');
  15. define('BX_DEV_TOOLS_NAVIGATION', 'navigation');
  16. define('BX_DEV_TOOLS_POLYGLOT', 'polyglot');
  17. define('BX_DEV_TOOLS_PERMISSIONS', 'permissions');
  18. class BxDevModule extends BxDolModule
  19. {
  20. public $aTools;
  21. function __construct($aModule)
  22. {
  23. parent::__construct($aModule);
  24. $this->aTools = array(
  25. array('name' => BX_DEV_TOOLS_SETTINGS, 'title' => '_adm_page_cpt_settings', 'icon' => 'bx-dev-mi-settings.svg'),
  26. array('name' => BX_DEV_TOOLS_POLYGLOT, 'title' => '_adm_page_cpt_polyglot', 'icon' => 'bx-dev-mi-polyglot.svg'),
  27. array('name' => BX_DEV_TOOLS_FORMS, 'title' => '_adm_page_cpt_builder_forms', 'icon' => 'bx-dev-mi-forms.svg'),
  28. array('name' => BX_DEV_TOOLS_NAVIGATION, 'title' => '_adm_page_cpt_builder_menus', 'icon' => 'bx-dev-mi-navigation.svg'),
  29. array('name' => BX_DEV_TOOLS_PAGES, 'title' => '_adm_page_cpt_builder_pages', 'icon' => 'bx-dev-mi-pages.svg'),
  30. //array('name' => BX_DEV_TOOLS_PERMISSIONS, 'title' => '_adm_page_cpt_builder_permissions', 'icon' => 'bx-dev-mi-permissions.png'),
  31. );
  32. }
  33. function getToolsList()
  34. {
  35. return $this->aTools;
  36. }
  37. public function actionResetHash($sType, $sModule = '')
  38. {
  39. $oDb = bx_instance('BxDolStudioInstallerQuery');
  40. $sResult = '';
  41. switch ($sType) {
  42. case 'system':
  43. $oHasher = bx_instance('BxDolInstallerHasher');
  44. $oDb->deleteModuleTrackFiles(BX_SYSTEM_MODULE_ID);
  45. $sResult = _t('_bx_dev_hash_' . ($oHasher->hashSystemFiles() ? 'msg' : 'err') . '_reset_hash_system');
  46. break;
  47. case 'modules':
  48. $oModuleQuery = BxDolModuleQuery::getInstance();
  49. if(!empty($sModule)) {
  50. $aNames = strpos($sModule, ',') !== false ? explode(',', $sModule) : array($sModule);
  51. $aModule = array();
  52. foreach($aNames as $aName)
  53. $aModules[] = $oModuleQuery->getModuleByName($aName);
  54. }
  55. else
  56. $aModules = $oModuleQuery->getModules();
  57. $aTmplVarsModules = array();
  58. if(!empty($aModules) && is_array($aModules))
  59. foreach($aModules as $aModule) {
  60. if($aModule['name'] == 'system')
  61. continue;
  62. $aConfig = BxDolInstallerUtils::getModuleConfig($aModule);
  63. $sPathInstaller = BX_DIRECTORY_PATH_MODULES . $aModule['path'] . 'install/installer.php';
  64. if(empty($aConfig) || !file_exists($sPathInstaller))
  65. continue;
  66. require_once($sPathInstaller);
  67. $sClassName = $aConfig['class_prefix'] . 'Installer';
  68. $oInstaller = new $sClassName($aConfig);
  69. $oDb->deleteModuleTrackFiles($aModule['id']);
  70. $aFiles = array();
  71. $oInstaller->hashFiles(BX_DIRECTORY_PATH_ROOT . 'modules/' . $aModule['path'], $aFiles);
  72. foreach($aFiles as $aFile)
  73. $oDb->insertModuleTrack($aModule['id'], $aFile);
  74. $aTmplVarsModules[] = array(
  75. 'module' => $aModule['title'],
  76. 'files' => count($aFiles)
  77. );
  78. }
  79. $sResult = $this->_oTemplate->parseHtmlByName('hash_modules.html', array(
  80. 'bx_repeat:modules' => $aTmplVarsModules
  81. ));
  82. break;
  83. }
  84. echo $sResult;
  85. exit;
  86. }
  87. public function actionExport()
  88. {
  89. $sType = bx_process_input(bx_get('type'));
  90. if(empty($sType))
  91. return echoJson([]);
  92. echoJson([
  93. 'url' => BX_DOL_URL_ROOT . bx_append_url_params($this->_oConfig->getBaseUri() . 'download', [
  94. 'type' => $sType,
  95. ]),
  96. 'eval' => $this->_oConfig->getJsObject('main') . '.onExport(oData);'
  97. ]);
  98. }
  99. public function actionDownload()
  100. {
  101. $sType = bx_process_input(bx_get('type'));
  102. if(empty($sType))
  103. return;
  104. $sMethod = '_eiExport' . bx_gen_method_name($sType);
  105. if(!method_exists($this, $sMethod))
  106. return;
  107. $mixedFull = ($mixedFull = bx_get('full')) !== false ? (int)$mixedFull != 0 : false;
  108. list($aMeta, $aData) = $this->$sMethod($mixedFull);
  109. $iNow = time();
  110. $sContent = json_encode([
  111. 'meta' => array_merge([
  112. 'version' => bx_get_ver(),
  113. 'date' => date('D, d M Y H:i:s', $iNow),
  114. 'full' => $mixedFull
  115. ], $aMeta),
  116. 'data' => $aData
  117. ]);
  118. header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
  119. header("Content-type: application/json");
  120. header("Content-Length: " . strlen($sContent));
  121. header("Content-Disposition: attachment; filename=\"" . $sType . ($mixedFull ? "_f" : "") . "_". date('d_m_Y', $iNow) . ".json\"");
  122. echo $sContent;
  123. exit;
  124. }
  125. public function actionImport()
  126. {
  127. $sType = bx_process_input(bx_get('type'));
  128. if(empty($sType))
  129. return echoJson([]);
  130. $aResult = $this->getPopupCodeImport([
  131. 'form_name' => 'bx-dev-' . $sType . '-import-full',
  132. 'form_action' => BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'import?type=' . $sType
  133. ]);
  134. if(!isset($aResult['code']) || (int)$aResult['code'] != 0)
  135. return echoJson($aResult);
  136. $sMethod = '_eiImport' . bx_gen_method_name($sType);
  137. if(!method_exists($this, $sMethod))
  138. return echoJson([]);
  139. echoJson($this->$sMethod($aResult['content']));
  140. }
  141. public function getPopupCodeImport($aParams)
  142. {
  143. $sJsObject = $this->_oConfig->getJsObject('main');
  144. $sForm = $aParams['form_name'];
  145. $aForm = [
  146. 'form_attrs' => [
  147. 'id' => $sForm,
  148. 'name' => $sForm,
  149. 'action' => $aParams['form_action'],
  150. 'method' => 'post',
  151. 'enctype' => 'multipart/form-data'
  152. ],
  153. 'params' => [
  154. 'db' => [
  155. 'submit_name' => 'save'
  156. ],
  157. ],
  158. 'inputs' => [
  159. 'file' => [
  160. 'type' => 'file',
  161. 'name' => 'file',
  162. 'caption' => '',
  163. 'value' => '',
  164. ],
  165. 'controls' => [
  166. 'type' => 'input_set', [
  167. 'type' => 'submit',
  168. 'name' => 'save',
  169. 'value' => _t('_bx_dev_btn_import_full'),
  170. ], [
  171. 'type' => 'button',
  172. 'name' => 'cancel',
  173. 'value' => _t('_bx_dev_btn_cancel'),
  174. 'attrs' => [
  175. 'class' => 'bx-def-margin-sec-left-auto',
  176. 'onclick' => '$(".bx-popup-applied:visible").dolPopupHide()'
  177. ]
  178. ]
  179. ]
  180. ]
  181. ];
  182. $oForm = new BxTemplStudioFormView($aForm);
  183. $oForm->initChecker();
  184. if($oForm->isSubmittedAndValid()) {
  185. $sError = _t('_bx_dev_err_cannot_perform');
  186. if(empty($_FILES['file']) || empty($_FILES['file']['tmp_name']))
  187. return ['code' => 1, 'msg' => $sError];
  188. $aFile = $_FILES['file'];
  189. $sFile = $aFile['tmp_name'];
  190. $rHandle = @fopen($sFile, "r");
  191. if(!$rHandle)
  192. return ['code' => 2, 'message' => $sError];
  193. $sContents = fread($rHandle, filesize($sFile));
  194. fclose($rHandle);
  195. $aContent = json_decode($sContents, true);
  196. if(!is_array($aContent) || empty($aContent['meta']) || empty($aContent['data']))
  197. return ['code' => 3, 'message' => $sError];
  198. return ['code' => 0, 'content' => $aContent];
  199. }
  200. return [
  201. 'popup' => BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-import-popup', _t('_bx_dev_txt_import_full_popup'), $this->_oTemplate->parseHtmlByName('import_popup.html', [
  202. 'js_object' => $sJsObject,
  203. 'form_id' => $sForm,
  204. 'form' => $oForm->getCode(true),
  205. ]))
  206. ];
  207. }
  208. /**
  209. *
  210. * Methods for Export/Import feature.
  211. *
  212. */
  213. protected function _eiExportForms($bModeFull = false)
  214. {
  215. $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_forms'));
  216. if(!$oGrid)
  217. return [];
  218. $aForms = [];
  219. $oGrid->oDb->getForms(['type' => 'export'], $aForms, false);
  220. if(empty($aForms) || !is_array($aForms))
  221. return [];
  222. $aMeta = [
  223. 'masks' => [
  224. 'form' => ['object', 'active'],
  225. 'display' => ['display_name'],
  226. 'input' => ['object', 'name', 'privacy', 'checker_func', 'checker_params', 'checker_error', 'db_pass', 'db_params'],
  227. 'display_input' => ['display_name', 'input_name', 'visible_for_levels', 'active', 'order']
  228. ]
  229. ];
  230. if($bModeFull) {
  231. $aMeta['masks'] = [
  232. 'form' => ['object', 'module', 'title', 'action', 'form_attrs', 'submit_name', 'table', 'key', 'uri', 'uri_title', 'params', 'deletable', 'active', 'override_class_name', 'override_class_file'],
  233. 'display' => ['display_name', 'module', 'object', 'title', 'view_mode'],
  234. 'input' => ['object', 'module', 'name', 'value', 'values', 'checked', 'type', 'caption_system', 'caption', 'info', 'help', 'icon', 'required', 'unique', 'collapsed', 'html', 'privacy', 'rateable', 'attrs', 'attrs_tr', 'attrs_wrapper', 'checker_func', 'checker_params', 'checker_error', 'db_pass', 'db_params', 'editable', 'deletable'],
  235. 'display_input' => ['display_name', 'input_name', 'visible_for_levels', 'active', 'order']
  236. ];
  237. }
  238. $aMfForm = $aMfDisplay = $aMfInput = $aMfDisplayInput = false;
  239. foreach($aMeta['masks'] as $sMask => $aMask)
  240. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  241. $aData = [];
  242. foreach($aForms as $aForm) {
  243. $sObject = $aForm['object'];
  244. $aDisplays = [];
  245. $oGrid->oDb->getDisplays(['type' => 'export_by_object', 'value' => $sObject], $aDisplays, false);
  246. $aListDisplays = [];
  247. $aDataDisplays = [];
  248. if(!empty($aDisplays) && is_array($aDisplays))
  249. foreach($aDisplays as $aDisplay) {
  250. $aListDisplays[] = $aDisplay['display_name'];
  251. $aDataDisplays[] = $aMfDisplay !== false ? array_intersect_key($aDisplay, $aMfDisplay) : $aDisplay;
  252. }
  253. $aInputs = [];
  254. $oGrid->oDb->getInputs(['type' => 'dump_inputs', 'value' => $sObject], $aInputs, false);
  255. $aDataInputs = [];
  256. if(!empty($aInputs) && is_array($aInputs))
  257. foreach($aInputs as $aInput)
  258. $aDataInputs[] = $aMfInput !== false ? array_intersect_key($aInput, $aMfInput) : $aInput;
  259. $aDisplayInputs = [];
  260. $oGrid->oDb->getInputs(['type' => 'dump_display_inputs', 'displays' => $aListDisplays], $aDisplayInputs, false);
  261. $aDataDisplayInputs = [];
  262. if(!empty($aDisplayInputs) && is_array($aDisplayInputs))
  263. foreach($aDisplayInputs as $aDisplayInput)
  264. $aDataDisplayInputs[] = $aMfDisplayInput !== false ? array_intersect_key($aDisplayInput, $aMfDisplayInput) : $aDisplayInput;
  265. $aData[] = [
  266. 'form' => $aMfForm !== false ? array_intersect_key($aForm, $aMfForm) : $aForm,
  267. 'displays' => $aDataDisplays,
  268. 'inputs' => $aDataInputs,
  269. 'display_inputs' => $aDataDisplayInputs
  270. ];
  271. }
  272. return [$aMeta, $aData];
  273. }
  274. protected function _eiExportMenus($bModeFull = false)
  275. {
  276. $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_nav_menus'));
  277. if(!$oGrid)
  278. return [];
  279. $aMenus = [];
  280. $oGrid->oDb->getMenus(['type' => 'export'], $aMenus, false);
  281. if(empty($aMenus) || !is_array($aMenus))
  282. return [];
  283. $aMeta = [
  284. 'masks' => [
  285. 'menu' => ['object', 'active'],
  286. 'set' => ['set_name'],
  287. 'item' => ['set_name', 'name', 'visible_for_levels', 'visibility_custom', 'hidden_on', 'hidden_on_cxt', 'hidden_on_pt', 'hidden_on_col', 'active', 'active_api', 'order']
  288. ]
  289. ];
  290. if($bModeFull) {
  291. $aMeta['masks'] = [
  292. 'menu' => ['object', 'title', 'set_name', 'module', 'template_id', 'deletable', 'active', 'override_class_name', 'override_class_file'],
  293. 'set' => ['set_name', 'module', 'title', 'deletable'],
  294. 'item' => ['parent_id', 'set_name', 'module', 'name', 'title_system', 'title', 'link', 'onclick', 'target', 'icon', 'addon', 'addon_cache', 'markers', 'submenu_object', 'submenu_popup', 'visible_for_levels', 'visibility_custom', 'hidden_on', 'hidden_on_cxt', 'hidden_on_pt', 'hidden_on_col', 'primary', 'collapsed', 'active', 'active_api', 'copyable', 'editable', 'order']
  295. ];
  296. }
  297. $aMfMenu = $aMfSet = $aMfItem = false;
  298. foreach($aMeta['masks'] as $sMask => $aMask)
  299. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  300. $aData = [];
  301. foreach($aMenus as $aMenu) {
  302. $aSet = [];
  303. $oGrid->oDb->getSets(['type' => 'export_by_name', 'value' => $aMenu['set_name']], $aSet, false);
  304. $aDataItems = [];
  305. if(!empty($aSet) && is_array($aSet)) {
  306. $aItems = [];
  307. $oGrid->oDb->getItems(['type' => 'export_by_set_name', 'value' => $aSet['set_name']], $aItems, false);
  308. if(!empty($aItems) && is_array($aItems))
  309. foreach($aItems as $aItem)
  310. $aDataItems[] = $aMfItem !== false ? array_intersect_key($aItem, $aMfItem) : $aItem;
  311. }
  312. $aData[] = [
  313. 'menu' => $aMfMenu !== false ? array_intersect_key($aMenu, $aMfMenu) : $aMenu,
  314. 'set' => !empty($aSet) && $aMfSet !== false ? array_intersect_key($aSet, $aMfSet) : $aSet,
  315. 'items' => $aDataItems,
  316. ];
  317. }
  318. return [$aMeta, $aData];
  319. }
  320. protected function _eiExportPages($bModeFull = false)
  321. {
  322. bx_import('BuilderPage', $this->_aModule);
  323. $oBuilderPage = new BxDevBuilderPage(['type' => '', 'page' => '', 'url' => '']);
  324. if(!$oBuilderPage)
  325. return [];
  326. $oBpDb = $oBuilderPage->getDb();
  327. $aPages = $oBpDb->getPages(['type' => 'export']);
  328. if(empty($aPages) || !is_array($aPages))
  329. return [];
  330. $aMeta = [
  331. 'masks' => [
  332. 'page' => ['object', 'visible_for_levels'],
  333. 'block' => ['object', 'cell_id', 'module', 'title_system', 'title', 'visible_for_levels', 'hidden_on', 'active', 'active_api', 'order']
  334. ]
  335. ];
  336. if($bModeFull) {
  337. $aMeta['masks'] = [
  338. 'page' => ['author', 'added', 'object', 'uri', 'title_system', 'title', 'module', 'cover', 'cover_image', 'cover_title', 'type_id', 'layout_id', 'sticky_columns', 'submenu', 'visible_for_levels', 'visible_for_levels_editable', 'url', 'content_info', 'meta_description', 'meta_keywords', 'meta_robots', 'cache_lifetime', 'cache_editable', 'inj_head', 'inj_footer', 'deletable', 'override_class_name', 'override_class_file'],
  339. 'block' => ['object', 'cell_id', 'module', 'title_system', 'title', 'designbox_id', 'class', 'submenu', 'tabs', 'async', 'visible_for_levels', 'hidden_on', 'type', 'content', 'content_empty', 'text', 'text_updated', 'help', 'cache_lifetime', 'deletable', 'copyable', 'active', 'active_api', 'order']
  340. ];
  341. }
  342. $aMfPage = $aMfBlock = false;
  343. foreach($aMeta['masks'] as $sMask => $aMask)
  344. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  345. $aData = [];
  346. foreach($aPages as $aPage) {
  347. $aBlocks = [];
  348. $oBpDb->getBlocks(['type' => 'export_by_object', 'value' => $aPage['object']], $aBlocks, false);
  349. $aDataBlocks = [];
  350. if(!empty($aBlocks) && is_array($aBlocks))
  351. foreach($aBlocks as $aBlock)
  352. $aDataBlocks[] = $aMfBlock !== false ? array_intersect_key($aBlock, $aMfBlock) : $aBlock;
  353. $aData[] = [
  354. 'page' => $aMfPage !== false ? array_intersect_key($aPage, $aMfPage) : $aPage,
  355. 'blocks' => $aDataBlocks,
  356. ];
  357. }
  358. return [$aMeta, $aData];
  359. }
  360. protected function _eiImportPages($aContent)
  361. {
  362. bx_import('BuilderPage', $this->_aModule);
  363. $oBuilderPage = new BxDevBuilderPage(['type' => '', 'page' => '', 'url' => '']);
  364. if(!$oBuilderPage)
  365. return [];
  366. $oBpDb = $oBuilderPage->getDb();
  367. $bModeFull = isset($aContent['meta']['full']) && (bool)$aContent['meta']['full'] === true;
  368. $aMfMenu = $aMfSet = $aMfItem = false;
  369. foreach($aContent['meta']['masks'] as $sMask => $aMask)
  370. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  371. $iData = 0;
  372. foreach($aContent['data'] as $aData) {
  373. $iData += 1;
  374. $sObject = $aData['page']['object'];
  375. if($bModeFull && !$oBpDb->isPageExists($sObject))
  376. $oBpDb->addPage($aData['page']);
  377. else
  378. $oBpDb->updatePageByObject($sObject, $aData['page']);
  379. foreach($aData['blocks'] as $aBlock) {
  380. $aFields = [
  381. 'object' => $aBlock['object'],
  382. 'module' => $aBlock['module'],
  383. 'title_system' => $aBlock['title_system'],
  384. 'title' => $aBlock['title']
  385. ];
  386. if($bModeFull && !$oBpDb->isBlockExists($aFields))
  387. $oBpDb->addBlock($aItem);
  388. else
  389. $oBpDb->updateBlockByFields($aFields, $aBlock);
  390. }
  391. }
  392. BxDolCacheUtilities::getInstance()->clear('db');
  393. return [
  394. 'msg' => _t('_bx_dev_msg_imported', $iData),
  395. 'eval' => $this->_oConfig->getJsObject('main') . '.onImport(oData);'
  396. ];
  397. }
  398. }
  399. /** @} */