1
0

BxDevModule.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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'], $aResult['disable'] != 0));
  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. 'disable' => [
  166. 'type' => 'switcher',
  167. 'name' => 'disable',
  168. 'caption' => _t('_bx_dev_txt_disable_before_import'),
  169. 'info' => '',
  170. 'value' => '1',
  171. 'checked' => 0,
  172. 'db' => [
  173. 'pass' => 'Int',
  174. ],
  175. ],
  176. 'controls' => [
  177. 'type' => 'input_set', [
  178. 'type' => 'submit',
  179. 'name' => 'save',
  180. 'value' => _t('_bx_dev_btn_import_full'),
  181. ], [
  182. 'type' => 'button',
  183. 'name' => 'cancel',
  184. 'value' => _t('_bx_dev_btn_cancel'),
  185. 'attrs' => [
  186. 'class' => 'bx-def-margin-sec-left-auto',
  187. 'onclick' => '$(".bx-popup-applied:visible").dolPopupHide()'
  188. ]
  189. ]
  190. ]
  191. ]
  192. ];
  193. $oForm = new BxTemplStudioFormView($aForm);
  194. $oForm->initChecker();
  195. if($oForm->isSubmittedAndValid()) {
  196. $sError = _t('_bx_dev_err_cannot_perform');
  197. if(empty($_FILES['file']) || empty($_FILES['file']['tmp_name']))
  198. return ['code' => 1, 'msg' => $sError];
  199. $aFile = $_FILES['file'];
  200. $sFile = $aFile['tmp_name'];
  201. $rHandle = @fopen($sFile, "r");
  202. if(!$rHandle)
  203. return ['code' => 2, 'message' => $sError];
  204. $sContents = fread($rHandle, filesize($sFile));
  205. fclose($rHandle);
  206. $aContent = json_decode($sContents, true);
  207. if(!is_array($aContent) || empty($aContent['meta']) || empty($aContent['data']))
  208. return ['code' => 3, 'message' => $sError];
  209. return ['code' => 0, 'content' => $aContent, 'disable' => $oForm->getCleanValue('disable')];
  210. }
  211. return [
  212. 'popup' => BxTemplStudioFunctions::getInstance()->popupBox('bx-dev-import-popup', _t('_bx_dev_txt_import_full_popup'), $this->_oTemplate->parseHtmlByName('import_popup.html', [
  213. 'js_object' => $sJsObject,
  214. 'form_id' => $sForm,
  215. 'form' => $oForm->getCode(true),
  216. ]))
  217. ];
  218. }
  219. /**
  220. *
  221. * Methods for Export/Import feature.
  222. *
  223. */
  224. protected function _eiExportForms($bModeFull = false)
  225. {
  226. $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_forms'));
  227. if(!$oGrid)
  228. return [];
  229. $aForms = [];
  230. $oGrid->oDb->getForms(['type' => 'export'], $aForms, false);
  231. if(empty($aForms) || !is_array($aForms))
  232. return [];
  233. $aMeta = [
  234. 'masks' => [
  235. 'form' => ['object', 'active'],
  236. 'display' => ['display_name'],
  237. 'input' => ['object', 'name', 'privacy', 'checker_func', 'checker_params', 'checker_error', 'db_pass', 'db_params'],
  238. 'display_input' => ['display_name', 'input_name', 'visible_for_levels', 'active', 'order']
  239. ]
  240. ];
  241. if($bModeFull) {
  242. $aMeta['masks'] = [
  243. 'form' => ['object', 'module', 'title', 'action', 'form_attrs', 'submit_name', 'table', 'key', 'uri', 'uri_title', 'params', 'deletable', 'active', 'override_class_name', 'override_class_file'],
  244. 'display' => ['display_name', 'module', 'object', 'title', 'view_mode'],
  245. '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'],
  246. 'display_input' => ['display_name', 'input_name', 'visible_for_levels', 'active', 'order']
  247. ];
  248. }
  249. $aMfForm = $aMfDisplay = $aMfInput = $aMfDisplayInput = false;
  250. foreach($aMeta['masks'] as $sMask => $aMask)
  251. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  252. $aData = [];
  253. foreach($aForms as $aForm) {
  254. $sObject = $aForm['object'];
  255. $aDisplays = [];
  256. $oGrid->oDb->getDisplays(['type' => 'export_by_object', 'value' => $sObject], $aDisplays, false);
  257. $aListDisplays = [];
  258. $aDataDisplays = [];
  259. if(!empty($aDisplays) && is_array($aDisplays))
  260. foreach($aDisplays as $aDisplay) {
  261. $aListDisplays[] = $aDisplay['display_name'];
  262. $aDataDisplays[] = $aMfDisplay !== false ? array_intersect_key($aDisplay, $aMfDisplay) : $aDisplay;
  263. }
  264. $aInputs = [];
  265. $oGrid->oDb->getInputs(['type' => 'dump_inputs', 'value' => $sObject], $aInputs, false);
  266. $aDataInputs = [];
  267. if(!empty($aInputs) && is_array($aInputs))
  268. foreach($aInputs as $aInput)
  269. $aDataInputs[] = $aMfInput !== false ? array_intersect_key($aInput, $aMfInput) : $aInput;
  270. $aDisplayInputs = [];
  271. $oGrid->oDb->getInputs(['type' => 'dump_display_inputs', 'displays' => $aListDisplays], $aDisplayInputs, false);
  272. $aDataDisplayInputs = [];
  273. if(!empty($aDisplayInputs) && is_array($aDisplayInputs))
  274. foreach($aDisplayInputs as $aDisplayInput)
  275. $aDataDisplayInputs[] = $aMfDisplayInput !== false ? array_intersect_key($aDisplayInput, $aMfDisplayInput) : $aDisplayInput;
  276. $aData[] = [
  277. 'form' => $aMfForm !== false ? array_intersect_key($aForm, $aMfForm) : $aForm,
  278. 'displays' => $aDataDisplays,
  279. 'inputs' => $aDataInputs,
  280. 'display_inputs' => $aDataDisplayInputs
  281. ];
  282. }
  283. return [$aMeta, $aData];
  284. }
  285. protected function _eiExportMenus($bModeFull = false)
  286. {
  287. $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_nav_menus'));
  288. if(!$oGrid)
  289. return [];
  290. $aMenus = [];
  291. $oGrid->oDb->getMenus(['type' => 'export'], $aMenus, false);
  292. if(empty($aMenus) || !is_array($aMenus))
  293. return [];
  294. $aMeta = [
  295. 'masks' => [
  296. 'menu' => ['object', 'active'],
  297. 'set' => ['set_name'],
  298. 'item' => ['set_name', 'name', 'visible_for_levels', 'visibility_custom', 'hidden_on', 'hidden_on_cxt', 'hidden_on_pt', 'hidden_on_col', 'active', 'active_api', 'order']
  299. ]
  300. ];
  301. if($bModeFull) {
  302. $aMeta['masks'] = [
  303. 'menu' => ['object', 'title', 'set_name', 'module', 'template_id', 'deletable', 'active', 'override_class_name', 'override_class_file'],
  304. 'set' => ['set_name', 'module', 'title', 'deletable'],
  305. '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']
  306. ];
  307. }
  308. $aMfMenu = $aMfSet = $aMfItem = false;
  309. foreach($aMeta['masks'] as $sMask => $aMask)
  310. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  311. $aData = [];
  312. foreach($aMenus as $aMenu) {
  313. $aSet = [];
  314. $oGrid->oDb->getSets(['type' => 'export_by_name', 'value' => $aMenu['set_name']], $aSet, false);
  315. $aDataItems = [];
  316. if(!empty($aSet) && is_array($aSet)) {
  317. $aItems = [];
  318. $oGrid->oDb->getItems(['type' => 'export_by_set_name', 'value' => $aSet['set_name']], $aItems, false);
  319. if(!empty($aItems) && is_array($aItems))
  320. foreach($aItems as $aItem)
  321. $aDataItems[] = $aMfItem !== false ? array_intersect_key($aItem, $aMfItem) : $aItem;
  322. }
  323. $aData[] = [
  324. 'menu' => $aMfMenu !== false ? array_intersect_key($aMenu, $aMfMenu) : $aMenu,
  325. 'set' => !empty($aSet) && $aMfSet !== false ? array_intersect_key($aSet, $aMfSet) : $aSet,
  326. 'items' => $aDataItems,
  327. ];
  328. }
  329. return [$aMeta, $aData];
  330. }
  331. protected function _eiExportPages($bModeFull = false)
  332. {
  333. bx_import('BuilderPage', $this->_aModule);
  334. $oBuilderPage = new BxDevBuilderPage(['type' => '', 'page' => '', 'url' => '']);
  335. if(!$oBuilderPage)
  336. return [];
  337. $oBpDb = $oBuilderPage->getDb();
  338. $aPages = $oBpDb->getPages(['type' => 'export']);
  339. if(empty($aPages) || !is_array($aPages))
  340. return [];
  341. $aMeta = [
  342. 'masks' => [
  343. 'page' => ['object', 'visible_for_levels'],
  344. 'block' => ['object', 'cell_id', 'module', 'title_system', 'title', 'visible_for_levels', 'hidden_on', 'active', 'active_api', 'order']
  345. ]
  346. ];
  347. if($bModeFull) {
  348. $aMeta['masks'] = [
  349. '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'],
  350. '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']
  351. ];
  352. }
  353. $aMfPage = $aMfBlock = false;
  354. foreach($aMeta['masks'] as $sMask => $aMask)
  355. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  356. $aData = [];
  357. foreach($aPages as $aPage) {
  358. $aBlocks = [];
  359. $oBpDb->getBlocks(['type' => 'export_by_object', 'value' => $aPage['object']], $aBlocks, false);
  360. $aDataBlocks = [];
  361. if(!empty($aBlocks) && is_array($aBlocks))
  362. foreach($aBlocks as $aBlock)
  363. $aDataBlocks[] = $aMfBlock !== false ? array_intersect_key($aBlock, $aMfBlock) : $aBlock;
  364. $aData[] = [
  365. 'page' => $aMfPage !== false ? array_intersect_key($aPage, $aMfPage) : $aPage,
  366. 'blocks' => $aDataBlocks,
  367. ];
  368. }
  369. return [$aMeta, $aData];
  370. }
  371. protected function _eiImportPages($aContent, $bDisable = false)
  372. {
  373. bx_import('BuilderPage', $this->_aModule);
  374. $oBuilderPage = new BxDevBuilderPage(['type' => '', 'page' => '', 'url' => '']);
  375. if(!$oBuilderPage)
  376. return [];
  377. $oBpDb = $oBuilderPage->getDb();
  378. $bModeFull = isset($aContent['meta']['full']) && (bool)$aContent['meta']['full'] === true;
  379. $aMfMenu = $aMfSet = $aMfItem = false;
  380. foreach($aContent['meta']['masks'] as $sMask => $aMask)
  381. ${'aMf' . bx_gen_method_name($sMask)} = array_flip($aMask);
  382. if($bDisable)
  383. $oBpDb->updateBlocks(['active' => 0, 'active_api' => 0]);
  384. $iData = 0;
  385. foreach($aContent['data'] as $aData) {
  386. $iData += 1;
  387. $sObject = $aData['page']['object'];
  388. if($bModeFull && !$oBpDb->isPageExists($sObject))
  389. $oBpDb->addPage($aData['page']);
  390. else
  391. $oBpDb->updatePageByObject($sObject, $aData['page']);
  392. foreach($aData['blocks'] as $aBlock) {
  393. $aFields = [
  394. 'object' => $aBlock['object'],
  395. 'module' => $aBlock['module'],
  396. 'title_system' => $aBlock['title_system'],
  397. 'title' => $aBlock['title']
  398. ];
  399. if($bModeFull && !$oBpDb->isBlockExists($aFields))
  400. $oBpDb->addBlock($aItem);
  401. else
  402. $oBpDb->updateBlockByFields($aFields, $aBlock);
  403. }
  404. }
  405. BxDolCacheUtilities::getInstance()->clear('db');
  406. return [
  407. 'msg' => _t('_bx_dev_msg_imported', $iData),
  408. 'eval' => $this->_oConfig->getJsObject('main') . '.onImport(oData);'
  409. ];
  410. }
  411. }
  412. /** @} */