BxDolStudioInstaller.php 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  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 UnaStudio UNA Studio
  7. * @{
  8. */
  9. define("BX_DOL_STUDIO_INSTALLER_SUCCESS", 0);
  10. define("BX_DOL_STUDIO_INSTALLER_FAILED", 1);
  11. /**
  12. * Base class for Installer classes in modules engine.
  13. *
  14. * The class contains different check functions which are used during the installation process.
  15. * An object of the class is created automatically with modules installer.
  16. * Installation/Uninstallation process can be controlled with config.php file located in [module]/install/ folder.
  17. *
  18. *
  19. * Example of usage:
  20. * refer to the BoonEx modules
  21. *
  22. *
  23. * Memberships/ACL:
  24. * Doesn't depend on user's membership.
  25. *
  26. *
  27. * Alerts:
  28. * no alerts available
  29. *
  30. */
  31. class BxDolStudioInstaller extends BxDolInstallerUtils
  32. {
  33. protected $oDb;
  34. protected $_aConfig;
  35. protected $_sBasePath;
  36. protected $_sHomePath;
  37. protected $_sModulePath;
  38. protected $_bUseFtp;
  39. protected $_aActions;
  40. protected $_bShowOnSuccess = false;
  41. public function __construct($aConfig)
  42. {
  43. parent::__construct();
  44. $this->oDb = bx_instance('BxDolStudioInstallerQuery');
  45. $this->_aConfig = $aConfig;
  46. $this->_sBasePath = BX_DIRECTORY_PATH_MODULES;
  47. $this->_sHomePath = $this->_sBasePath . $aConfig['home_dir'];
  48. $this->_sModulePath = $this->_sBasePath . $aConfig['home_dir'];
  49. $this->_bUseFtp = BX_FORCE_USE_FTP_FILE_TRANSFER;
  50. $this->_aActions = array(
  51. 'perform_install' => array(
  52. 'title' => '',
  53. 'success' => _t('_adm_msg_modules_success_install'),
  54. 'failed' => ''
  55. ),
  56. 'perform_uninstall' => array(
  57. 'title' => '',
  58. 'success' => _t('_adm_msg_modules_success_uninstall'),
  59. 'failed' => ''
  60. ),
  61. 'perform_enable' => array(
  62. 'title' => '',
  63. 'success' => _t('_adm_msg_modules_success_enable'),
  64. 'failed' => ''
  65. ),
  66. 'perform_disable' => array(
  67. 'title' => '',
  68. 'success' => _t('_adm_msg_modules_success_disable'),
  69. 'failed' => ''
  70. ),
  71. 'check_script_version' => array(
  72. 'title' => _t('_adm_txt_modules_check_script_version'),
  73. ),
  74. 'check_dependencies' => array(
  75. 'title' => _t('_adm_txt_modules_check_dependencies'),
  76. ),
  77. 'show_introduction' => array(
  78. 'title' => _t('_adm_txt_modules_show_introduction'),
  79. ),
  80. 'move_sources' => array(
  81. 'title' => _t('_adm_txt_modules_move_sources'),
  82. ),
  83. 'execute_sql' => array(
  84. 'title' => _t('_adm_txt_modules_execute_sql'),
  85. ),
  86. 'install_language' => array(
  87. 'title' => _t('_adm_txt_modules_install_language'),
  88. ),
  89. 'update_languages' => array(
  90. 'title' => _t('_adm_txt_modules_update_languages'),
  91. ),
  92. 'update_relations' => array(
  93. 'title' => _t('_adm_txt_modules_update_relations'),
  94. ),
  95. 'update_relations_for_all' => array(
  96. 'title' => _t('_adm_txt_modules_update_relations_for_all'),
  97. ),
  98. 'process_connections' => array(
  99. 'title' => _t('_adm_txt_modules_process_connections'),
  100. ),
  101. 'process_deleted_profiles' => array(
  102. 'title' => _t('_adm_txt_modules_process_deleted_profiles'),
  103. ),
  104. 'process_menu_triggers' => array(
  105. 'title' => _t('_adm_txt_modules_process_menu_triggers'),
  106. ),
  107. 'process_page_triggers' => array(
  108. 'title' => _t('_adm_txt_modules_process_page_triggers'),
  109. ),
  110. 'process_storages' => array(
  111. 'title' => _t('_adm_txt_modules_process_storages'),
  112. ),
  113. 'process_esearches' => array(
  114. 'title' => _t('_adm_txt_modules_process_esearches'),
  115. ),
  116. 'register_transcoders' => array(
  117. 'title' => _t('_adm_txt_modules_register_transcoders'),
  118. ),
  119. 'unregister_transcoders' => array(
  120. 'title' => _t('_adm_txt_modules_unregister_transcoders'),
  121. ),
  122. 'clear_db_cache' => array(
  123. 'title' => _t('_adm_txt_modules_clear_db_cache'),
  124. ),
  125. 'show_conclusion' => array(
  126. 'title' => _t('_adm_txt_modules_show_conclusion'),
  127. ),
  128. );
  129. $this->_aNonHashableFiles = array(
  130. 'install',
  131. 'updates'
  132. );
  133. }
  134. public function install($aParams, $bAutoEnable = false)
  135. {
  136. //--- Auto uninstall before install ---//
  137. $this->disable($aParams);
  138. $this->uninstall($aParams);
  139. $bAutoEnable = $bAutoEnable || (isset($aParams['auto_enable']) && (bool)$aParams['auto_enable']);
  140. $bHtmlResponce = isset($aParams['html_response']) && (bool)$aParams['html_response'];
  141. //--- Check whether the module was already installed ---//
  142. if($this->oDb->isModule($this->_aConfig['home_uri']))
  143. return array(
  144. 'message' => _t('_adm_err_modules_already_installed'),
  145. 'result' => false
  146. );
  147. $aResult = array();
  148. bx_alert('system', 'before_install', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  149. if ($aResult && !$aResult['result'])
  150. return $aResult;
  151. //--- Check mandatory settings ---//
  152. if($this->oDb->isModuleParamsUsed($this->_aConfig['home_uri'], $this->_aConfig['home_dir'], $this->_aConfig['db_prefix'], $this->_aConfig['class_prefix']))
  153. return array(
  154. 'message' => _t('_adm_txt_modules_params_used'),
  155. 'result' => false
  156. );
  157. //--- Check version compatibility ---//
  158. if(!$this->_isCompatibleWith())
  159. return array(
  160. 'message' => $this->_displayResult('check_script_version', false, '_adm_err_modules_wrong_version_script', $bHtmlResponce),
  161. 'result' => false
  162. );
  163. //--- Check for available translations ---//
  164. $oFile = $this->_getFileManager();
  165. $sModuleUri = $this->_aConfig['home_uri'];
  166. $aLanguages = $this->oDb->getModulesBy(array('type' => 'languages'));
  167. foreach($aLanguages as $aLanguage) {
  168. if($aLanguage['uri'] == 'en')
  169. continue;
  170. $aLanguageConfig = self::getModuleConfig(BX_DIRECTORY_PATH_MODULES . $aLanguage['path'] . '/install/config.php');
  171. if(empty($aLanguageConfig))
  172. continue;
  173. if(!isset($aLanguageConfig['includes'][$sModuleUri]) || empty($aLanguageConfig['includes'][$sModuleUri]))
  174. continue;
  175. $sSrcPath = 'modules/' . $aLanguage['path'] . 'install/data/' . $aLanguageConfig['includes'][$sModuleUri];
  176. $sDstPath = $aLanguageConfig['includes'][$sModuleUri];
  177. $oFile->copy($sSrcPath, $sDstPath);
  178. }
  179. //--- Check actions ---//
  180. $aResult = $this->_perform('install', $aParams);
  181. if($aResult['result']) {
  182. $sDependencies = "";
  183. if(isset($this->_aConfig['install']['check_dependencies']) && (int)$this->_aConfig['install']['check_dependencies'] == 1 && isset($this->_aConfig['dependencies']) && is_array($this->_aConfig['dependencies']))
  184. $this->_aConfig['dependencies'] = array_keys($this->_aConfig['dependencies']);
  185. $iModuleId = $this->oDb->insertModule($this->_aConfig);
  186. $sTitleKey = BxDolModule::getTitleKey($this->_aConfig['home_uri']);
  187. $oLanguages = BxDolStudioLanguagesUtils::getInstance();
  188. $oLanguages->addLanguageString($sTitleKey, $this->_aConfig['title']);
  189. $oLanguages->compileLanguage();
  190. BxDolStudioInstallerUtils::getInstance()->checkModules();
  191. $aFiles = array();
  192. $this->hashFiles($this->_sModulePath, $aFiles);
  193. foreach($aFiles as $aFile)
  194. $this->oDb->insertModuleTrack($iModuleId, $aFile);
  195. $this->cleanupMemoryAfterAction($this->_aConfig['home_uri'], $iModuleId);
  196. if(!empty($this->_aConfig['install_success']))
  197. $this->_perform('install_success', $aParams);
  198. }
  199. else {
  200. if(!empty($this->_aConfig['install_failed']))
  201. $this->_perform('install_failed', $aParams);
  202. }
  203. bx_alert('system', 'install', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  204. if($aResult['result'] && $bAutoEnable) {
  205. $aResultEnable = $this->enable($aParams);
  206. $aResult['result'] = $aResult['result'] & $aResultEnable['result'];
  207. $aResult['message'] = $aResult['message'] . $aResultEnable['message'];
  208. }
  209. return $aResult;
  210. }
  211. public function uninstall($aParams, $bAutoDisable = false)
  212. {
  213. $bAutoDisable = $bAutoDisable || (isset($aParams['auto_disable']) && (bool)$aParams['auto_disable']);
  214. $bHtmlResponce = isset($aParams['html_response']) && (bool)$aParams['html_response'];
  215. //--- Check whether the module was already uninstalled ---//
  216. if(!$this->oDb->isModule($this->_aConfig['home_uri']))
  217. return array(
  218. 'message' => _t('_adm_err_modules_already_uninstalled'),
  219. 'result' => false
  220. );
  221. if($bAutoDisable) {
  222. $aResultDisable = $this->disable($aParams);
  223. if(!$aResultDisable['result'])
  224. return $aResultDisable;
  225. }
  226. $aResult = array();
  227. bx_alert('system', 'before_uninstall', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  228. if ($aResult && !$aResult['result'])
  229. return $aResult;
  230. //--- Check for dependent modules ---//
  231. $bDependent = false;
  232. $aDependents = $this->oDb->getDependent($this->_aConfig['home_uri']);
  233. if(is_array($aDependents) && !empty($aDependents)) {
  234. $bDependent = true;
  235. $sMessage = '<br />' . _t('_adm_err_modules_wrong_dependency_uninstall') . '<br />';
  236. foreach($aDependents as $aDependent)
  237. $sMessage .= $aDependent['title'] . '<br />';
  238. }
  239. if($bDependent)
  240. return array(
  241. 'message' => $this->_displayResult('check_dependencies', false, $sMessage, $bHtmlResponce),
  242. 'result' => false
  243. );
  244. $aResult = $this->_perform('uninstall', $aParams);
  245. if($aResult['result']) {
  246. $iModuleId = $this->oDb->deleteModule($this->_aConfig);
  247. $sTitleKey = BxDolModule::getTitleKey($this->_aConfig['home_uri']);
  248. $oLanguages = BxDolStudioLanguagesUtils::getInstance();
  249. $oLanguages->deleteLanguageString($sTitleKey);
  250. $oLanguages->compileLanguage();
  251. $this->cleanupMemoryAfterAction($this->_aConfig['home_uri'], $iModuleId);
  252. if(!empty($this->_aConfig['uninstall_success']))
  253. $this->_perform('uninstall_success', $aParams);
  254. }
  255. else {
  256. if(!empty($this->_aConfig['uninstall_failed']))
  257. $this->_perform('uninstall_failed', $aParams);
  258. }
  259. if($bAutoDisable) {
  260. $aResult['result'] = $aResultDisable['result'] & $aResult['result'];
  261. $aResult['message'] = $aResultDisable['message'] . $aResult['message'];
  262. }
  263. bx_alert('system', 'uninstall', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  264. return $aResult;
  265. }
  266. public function delete($aParams)
  267. {
  268. $aError = array(
  269. 'message' => _t('_adm_err_modules_cannot_remove_package'),
  270. 'result' => false
  271. );
  272. $oFile = $this->_getFileManager();
  273. if(empty($oFile))
  274. return $aError;
  275. if(!$oFile->delete('modules/' . $this->_aConfig['home_dir']))
  276. return $aError;
  277. return array(
  278. 'message' => '', //_t('_adm_msg_modules_success_delete'),
  279. 'result' => true
  280. );
  281. }
  282. public function recompile($aParams)
  283. {
  284. $oLanguages = BxDolStudioLanguagesUtils::getInstance();
  285. $aResult = array('message' => '', 'result' => false);
  286. $aLanguages = $this->oDb->getLanguages();
  287. if (isAdmin() && !empty($aLanguages)) {
  288. $this->_updateLanguage(false, current($aLanguages));
  289. $bResult = false;
  290. foreach($aLanguages as $aLanguage) {
  291. $bResult = $this->_updateLanguage(true, $aLanguage) && $oLanguages->compileLanguage($aLanguage['id']);
  292. $aResult['message'] .= $aLanguage['title'] . ': <span style="color:' . ($bResult ? 'green' : 'red') . '">' . _t($bResult ? '_adm_txt_modules_process_action_success' : '_adm_txt_modules_process_action_failed') . '</span><br />';
  293. $aResult['result'] |= $bResult;
  294. }
  295. }
  296. return $aResult;
  297. }
  298. public function enable($aParams)
  299. {
  300. //--- Auto disable before enable ---//
  301. $this->disable($aParams);
  302. $aModule = $this->oDb->getModuleByUri($this->_aConfig['home_uri']);
  303. //--- Check whether the module is installed ---//
  304. if(empty($aModule) || !is_array($aModule))
  305. return array(
  306. 'message' => _t('_adm_err_modules_module_not_installed'),
  307. 'result' => false
  308. );
  309. //--- Check whether the module is already enabled ---//
  310. if((int)$aModule['enabled'] != 0)
  311. return array(
  312. 'message' => _t('_adm_err_modules_already_enabled'),
  313. 'result' => false
  314. );
  315. $aResult = array();
  316. if(!empty($this->_aConfig['before_enable'])) {
  317. $aResult = $this->_perform('before_enable', $aParams);
  318. if($aResult && !$aResult['result'])
  319. return $aResult;
  320. }
  321. $aResult = array();
  322. bx_alert('system', 'before_enable', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  323. if ($aResult && !$aResult['result'])
  324. return $aResult;
  325. $aResult = $this->_perform('enable', $aParams);
  326. if($aResult['result']) {
  327. $this->oDb->enableModuleByUri($aModule['uri']);
  328. $this->cleanupMemoryAfterAction($aModule['uri'], $aModule['id']);
  329. if(!empty($this->_aConfig['enable_success']))
  330. $this->_perform('enable_success', $aParams);
  331. }
  332. else {
  333. if(!empty($this->_aConfig['enable_failed']))
  334. $this->_perform('enable_failed', $aParams);
  335. }
  336. bx_alert('system', 'enable', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  337. return $aResult;
  338. }
  339. public function disable($aParams)
  340. {
  341. $bHtmlResponce = isset($aParams['html_response']) && (bool)$aParams['html_response'];
  342. $aModule = $this->oDb->getModuleByUri($this->_aConfig['home_uri']);
  343. //--- Check whether the module is installed ---//
  344. if(empty($aModule) || !is_array($aModule))
  345. return array(
  346. 'message' => _t('_adm_err_modules_module_not_installed'),
  347. 'result' => false
  348. );
  349. //--- Check whether the module is already disabled ---//
  350. if((int)$aModule['enabled'] == 0)
  351. return array(
  352. 'message' => _t('_adm_err_modules_already_disabled'),
  353. 'result' => false
  354. );
  355. $aResult = array();
  356. if(!empty($this->_aConfig['before_disable'])) {
  357. $aResult = $this->_perform('before_disable', $aParams);
  358. if($aResult && !$aResult['result'])
  359. return $aResult;
  360. }
  361. $aResult = array();
  362. bx_alert('system', 'before_disable', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  363. if ($aResult && !$aResult['result'])
  364. return $aResult;
  365. //--- Check for dependent modules ---//
  366. $bDependent = false;
  367. $aDependents = $this->oDb->getDependent($this->_aConfig['home_uri']);
  368. if(is_array($aDependents) && !empty($aDependents)) {
  369. $bDependent = true;
  370. $sMessage = '<br />' . _t('_adm_err_modules_wrong_dependency_disable') . '<br />';
  371. foreach($aDependents as $aDependent)
  372. $sMessage .= $aDependent['title'] . '<br />';
  373. }
  374. if($bDependent)
  375. return array(
  376. 'message' => $this->_displayResult('check_dependencies', false, $sMessage, $bHtmlResponce),
  377. 'result' => false
  378. );
  379. $aResult = $this->_perform('disable', $aParams);
  380. if($aResult['result']) {
  381. $this->oDb->disableModuleByUri($aModule['uri']);
  382. $this->cleanupMemoryAfterAction($aModule['uri'], $aModule['id']);
  383. if(!empty($this->_aConfig['disable_success']))
  384. $this->_perform('disable_success', $aParams);
  385. }
  386. else {
  387. if(!empty($this->_aConfig['disable_failed']))
  388. $this->_perform('disable_failed', $aParams);
  389. }
  390. bx_alert('system', 'disable', 0, false, array ('config' => $this->_aConfig, 'result' => &$aResult));
  391. return $aResult;
  392. }
  393. //--- Get/Set Methods ---//
  394. public function getVendor()
  395. {
  396. return $this->_aConfig['vendor'];
  397. }
  398. public function getName()
  399. {
  400. return $this->_aConfig['name'];
  401. }
  402. public function getTitle()
  403. {
  404. return $this->_aConfig['title'];
  405. }
  406. public function getHomeDir()
  407. {
  408. return $this->_aConfig['home_dir'];
  409. }
  410. //--- Action Methods ---//
  411. protected function actionOperationFailed($mixedResult)
  412. {
  413. return _t('_adm_err_modules_process_action_failed');
  414. }
  415. protected function actionCheckDependencies($sOperation)
  416. {
  417. $sContent = '';
  418. if(in_array($sOperation, array('install', 'enable', 'update'))) {
  419. if(!isset($this->_aConfig['dependencies']) || !is_array($this->_aConfig['dependencies']))
  420. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  421. foreach($this->_aConfig['dependencies'] as $sModuleUri => $sModuleTitle)
  422. if(!$this->oDb->isModule($sModuleUri) || !$this->oDb->isEnabled($sModuleUri))
  423. $sContent .= $sModuleTitle . '<br />';
  424. if(!empty($sContent))
  425. $sContent = '<br />' . _t('_adm_err_modules_wrong_dependency_install') . '<br />' . $sContent;
  426. }
  427. return empty($sContent) ? BX_DOL_STUDIO_INSTALLER_SUCCESS : array('code' => BX_DOL_STUDIO_INSTALLER_FAILED, 'content' => $sContent);
  428. }
  429. protected function actionCheckDependenciesFailed($mixedResult)
  430. {
  431. return $mixedResult['content'];
  432. }
  433. protected function actionShowIntroduction($sOperation)
  434. {
  435. if(!isset($this->_aConfig[$sOperation . '_info']['introduction']))
  436. return BX_DOL_STUDIO_INSTALLER_FAILED;
  437. $sPath = $this->_sHomePath . 'install/info/' . $this->_aConfig[$sOperation . '_info']['introduction'];
  438. return file_exists($sPath) ? array("code" => BX_DOL_STUDIO_INSTALLER_SUCCESS, "content" => file_get_contents($sPath)) : BX_DOL_STUDIO_INSTALLER_FAILED;
  439. }
  440. protected function actionShowConclusion($sOperation)
  441. {
  442. if(!isset($this->_aConfig[$sOperation . '_info']['conclusion']))
  443. return BX_DOL_STUDIO_INSTALLER_FAILED;
  444. $sPath = $this->_sHomePath . 'install/info/' . $this->_aConfig[$sOperation . '_info']['conclusion'];
  445. return file_exists($sPath) ? array("code" => BX_DOL_STUDIO_INSTALLER_SUCCESS, "content" => file_get_contents($sPath)) : BX_DOL_STUDIO_INSTALLER_FAILED;
  446. }
  447. protected function actionMoveSources($sOperation)
  448. {
  449. $oFile = $this->_getFileManager();
  450. $aInstalled = array_merge(array('system'), $this->oDb->getModulesUri());
  451. $bResult = true;
  452. foreach($this->_aConfig['includes'] as $sUri => $sPath) {
  453. if(!in_array($sUri, $aInstalled) || empty($sPath))
  454. continue;
  455. if($sOperation == 'install') {
  456. $sSrcPath = 'modules/' . $this->_aConfig['home_dir'] . 'install/data/' . $sPath;
  457. $sDstPath = $sPath;
  458. $bResult &= $oFile->copy($sSrcPath, $sDstPath);
  459. } else if($sOperation == 'uninstall')
  460. $bResult &= $oFile->delete($sPath);
  461. }
  462. return $bResult ? BX_DOL_STUDIO_INSTALLER_SUCCESS : BX_DOL_STUDIO_INSTALLER_FAILED;
  463. }
  464. protected function actionExecuteSql($sOperation)
  465. {
  466. switch($sOperation) {
  467. case 'install':
  468. $this->actionExecuteSql('disable');
  469. $this->actionExecuteSql('uninstall');
  470. break;
  471. case 'enable':
  472. $this->actionExecuteSql('disable');
  473. break;
  474. }
  475. $mixedResult = $this->oDb->executeSQL($this->_sHomePath . 'install/sql/' . $sOperation . '.sql', $this->getMarkersForDb());
  476. return $mixedResult === true ? BX_DOL_STUDIO_INSTALLER_SUCCESS : array('code' => BX_DOL_STUDIO_INSTALLER_FAILED, 'content' => $mixedResult);
  477. }
  478. protected function actionExecuteSqlFailed($mixedResult)
  479. {
  480. if(is_int($mixedResult))
  481. return $this->actionOperationFailed($mixedResult);
  482. $sResult = _t('_adm_err_modules_wrong_mysql_query') . '<br />';
  483. foreach($mixedResult['content'] as $aQuery) {
  484. $sResult .= _t('_adm_err_modules_wrong_mysql_query_msg', $aQuery['error']) . '<br />';
  485. $sResult .= '<pre>' . $aQuery['query'] . '</pre>';
  486. }
  487. return $sResult;
  488. }
  489. protected function actionInstallLanguage($sOperation)
  490. {
  491. $oLanguages = BxDolStudioLanguagesUtils::getInstance();
  492. $sLanguage = isset($this->_aConfig['home_uri']) ? $this->_aConfig['home_uri'] : '';
  493. $bResult = true;
  494. if($sOperation == 'install')
  495. $bResult = $oLanguages->installLanguage(array('name' => $this->_aConfig['name'], 'path' => $this->_aConfig['home_dir'], 'uri' => $this->_aConfig['home_uri'], 'lang_category' => $this->_aConfig['language_category']), false);
  496. return $bResult && $oLanguages->compileLanguage(0, true) ? BX_DOL_STUDIO_INSTALLER_SUCCESS : BX_DOL_STUDIO_INSTALLER_FAILED;
  497. }
  498. protected function actionUpdateLanguages($sOperation)
  499. {
  500. if(!isset($this->_aConfig['language_category']) || empty($this->_aConfig['language_category']))
  501. return BX_DOL_STUDIO_INSTALLER_FAILED;
  502. $oLanguages = BxDolStudioLanguagesUtils::getInstance();
  503. $bResult = true;
  504. $aResult = array();
  505. //--- Process Language Category ---//
  506. if($sOperation == 'install')
  507. $iCategoryId = $oLanguages->addLanguageCategory($this->_aConfig['language_category']);
  508. //--- Process languages' key=>value pears ---//
  509. $aModule = array(
  510. 'name' => $this->_aConfig['name'],
  511. 'path' => $this->_aConfig['home_dir'],
  512. 'uri' => $this->_aConfig['home_uri'],
  513. 'lang_category' => $this->_aConfig['language_category']
  514. );
  515. if($sOperation == 'install')
  516. $bResult = $oLanguages->restoreLanguage(0, $aModule, false);
  517. else if($sOperation == 'uninstall')
  518. $bResult = $oLanguages->removeLanguageByModule($aModule, false);
  519. if($sOperation == 'uninstall' && $bResult)
  520. $oLanguages->deleteLanguageCategory($this->_aConfig['language_category']);
  521. return $bResult && $oLanguages->compileLanguage(0, true) ? BX_DOL_STUDIO_INSTALLER_SUCCESS : BX_DOL_STUDIO_INSTALLER_FAILED;
  522. }
  523. /**
  524. * NOTE. The action is ONLY needed for dependent module to let
  525. * Notifications based module(s) know that he(they) should
  526. * update (request and save) handlers from this dependent module.
  527. */
  528. protected function actionUpdateRelations($sOperation)
  529. {
  530. if(!in_array($sOperation, array('install', 'uninstall', 'enable', 'disable')))
  531. return BX_DOL_STUDIO_INSTALLER_FAILED;
  532. if(empty($this->_aConfig['relations']) || !is_array($this->_aConfig['relations']))
  533. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  534. foreach($this->_aConfig['relations'] as $sModule) {
  535. if(!$this->oDb->isModuleByName($sModule))
  536. continue;
  537. $aRelation = $this->oDb->getRelationsBy(array('type' => 'module', 'value' => $sModule));
  538. if(empty($aRelation) || empty($aRelation['on_' . $sOperation]) || !BxDolRequest::serviceExists($aRelation['module'], $aRelation['on_' . $sOperation]))
  539. continue;
  540. BxDolService::call($aRelation['module'], $aRelation['on_' . $sOperation], array($this->_aConfig['home_uri']));
  541. }
  542. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  543. }
  544. /**
  545. * NOTE. The action is ONLY needed for Notifications based modules
  546. * to update (request and save) handlers from all dependent modules.
  547. */
  548. protected function actionUpdateRelationsForAll($sOperation)
  549. {
  550. if(!in_array($sOperation, array('enable', 'disable')))
  551. return BX_DOL_STUDIO_INSTALLER_FAILED;
  552. if($sOperation == 'enable')
  553. $this->oDb->insertRelation($this->_aConfig['name'], $this->_aConfig['relation_handlers']);
  554. $aRelation = $this->oDb->getRelationsBy(array('type' => 'module', 'value' => $this->_aConfig['name']));
  555. if(empty($aRelation) || empty($aRelation['on_' . $sOperation]))
  556. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  557. $aModules = $this->oDb->getModulesBy(array('type' => 'all', 'active' => 1));
  558. foreach($aModules as $aModule) {
  559. $aConfig = self::getModuleConfig($aModule);
  560. if(!empty($aConfig['relations']) && is_array($aConfig['relations']) && in_array($this->_aConfig['name'], $aConfig['relations']))
  561. BxDolService::call($this->_aConfig['name'], $aRelation['on_' . $sOperation], array($aModule['uri']));
  562. }
  563. if($sOperation == 'disable')
  564. $this->oDb->deleteRelation($this->_aConfig['name']);
  565. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  566. }
  567. /**
  568. *
  569. * Connections objects associated with module data. It must be defined which content is associated with the connection.
  570. * The key is connection object name and value is array (possible array values: type, conn, table, field_id).
  571. * If 'type' == 'profiles', then it is considered profiles connection and other possible param is 'conn' ('initiator', 'content' or 'both')
  572. * If 'type' == 'custom' (or ommited), then other possible params are 'conn', 'table' and 'field_id'
  573. * @param string $sOperation - operation type.
  574. */
  575. protected function actionProcessConnections($sOperation)
  576. {
  577. if(!in_array($sOperation, array('uninstall')) || empty($this->_aConfig['connections']))
  578. return BX_DOL_STUDIO_INSTALLER_FAILED;
  579. foreach($this->_aConfig['connections'] as $sObjectConnections => $a) {
  580. $o = BxDolConnection::getObjectInstance($sObjectConnections);
  581. if(!$o)
  582. continue;
  583. $sFuncSuffix = 'DeleteInitiatorAndContent';
  584. if (isset($a['conn']) && 'initiator' == $a['conn'])
  585. $sFuncSuffix = 'DeleteInitiator';
  586. elseif (isset($a['conn']) && 'content' == $a['conn'])
  587. $sFuncSuffix = 'DeleteContent';
  588. if (isset($a['type']) && 'profiles' == $a['type']) {
  589. $sFunc = 'onModuleProfile' . $sFuncSuffix;
  590. $o->$sFunc($this->_aConfig['name']);
  591. } else {
  592. $sFunc = 'onModule' . $sFuncSuffix;
  593. $o->$sFunc($a['table'], $a['field_id']);
  594. }
  595. }
  596. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  597. }
  598. /**
  599. *
  600. * Process the list of menu triggers provided in config array.
  601. * It must be specified in the module which adds menu item and in modules where menu items are added, @see BxDolMenu::processMenuTrigger
  602. * @param string $sOperation - operation type.
  603. */
  604. protected function actionProcessMenuTriggers($sOperation)
  605. {
  606. if(empty($this->_aConfig['menu_triggers']))
  607. return BX_DOL_STUDIO_INSTALLER_FAILED;
  608. foreach($this->_aConfig['menu_triggers'] as $sMenuTriggerName)
  609. BxDolMenu::processMenuTrigger($sMenuTriggerName);
  610. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  611. }
  612. /**
  613. *
  614. * Process the list of page triggers provided in config array.
  615. * It must be specified in the module which adds page block and in modules where page blocks are added, @see BxDolPage::processPageTrigger
  616. * @param string $sOperation - operation type.
  617. */
  618. protected function actionProcessPageTriggers($sOperation)
  619. {
  620. if(empty($this->_aConfig['page_triggers']))
  621. return BX_DOL_STUDIO_INSTALLER_FAILED;
  622. foreach($this->_aConfig['page_triggers'] as $sPageTriggerName)
  623. BxDolPage::processPageTrigger($sPageTriggerName);
  624. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  625. }
  626. protected function actionProcessDeletedProfiles($sOperation)
  627. {
  628. if(!in_array($sOperation, array('install', 'uninstall', 'enable', 'disable')))
  629. return BX_DOL_STUDIO_INSTALLER_FAILED;
  630. $o = BxDolProfileQuery::getInstance();
  631. $o->processDeletedProfiles();
  632. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  633. }
  634. /**
  635. *
  636. * Storage objects to automatically delete files from upon module uninstallation.
  637. * Note. Don't add storage objects used in transcoder objects.
  638. * @param string $sOperation - operation type.
  639. */
  640. protected function actionProcessStorages($sOperation)
  641. {
  642. if(empty($this->_aConfig['storages']))
  643. return BX_DOL_STUDIO_INSTALLER_FAILED;
  644. // check if module is already waiting while files are deleting
  645. if(self::isModulePendingUninstall($this->_aConfig['home_uri']))
  646. return array(
  647. 'code' => BX_DOL_STUDIO_INSTALLER_FAILED,
  648. 'content' => _t('_adm_err_modules_pending_uninstall_already'),
  649. );
  650. $bSetModulePendingUninstall = false;
  651. // queue for deletion storage files
  652. foreach($this->_aConfig['storages'] as $s)
  653. if(($o = BxDolStorage::getObjectInstance($s)) && $o->queueFilesForDeletionFromObject())
  654. $bSetModulePendingUninstall = true;
  655. // delete comments and queue for deletion comments attachments
  656. $iFiles = 0;
  657. BxDolCmts::onModuleUninstall($this->_aConfig['name'], $iFiles);
  658. if($iFiles)
  659. $bSetModulePendingUninstall = true;
  660. // if some files were added to the queue, set module as pending uninstall
  661. if ($bSetModulePendingUninstall) {
  662. self::setModulePendingUninstall($this->_aConfig['home_uri']);
  663. return array(
  664. 'code' => BX_DOL_STUDIO_INSTALLER_FAILED,
  665. 'content' => _t('_adm_err_modules_pending_uninstall'),
  666. );
  667. }
  668. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  669. }
  670. protected function actionProcessStoragesFailed($mixedResult)
  671. {
  672. if(is_int($mixedResult))
  673. return $this->actionOperationFailed($mixedResult);
  674. return $mixedResult['content'];
  675. }
  676. /**
  677. *
  678. * Process the list of extended search forms provided in config array.
  679. * @param string $sOperation - operation type.
  680. */
  681. protected function actionProcessEsearches($sOperation)
  682. {
  683. if(empty($this->_aConfig['esearches']))
  684. return BX_DOL_STUDIO_INSTALLER_FAILED;
  685. foreach($this->_aConfig['esearches'] as $sObject) {
  686. if(in_array($sOperation, array('install', 'enable', 'enable_success')))
  687. BxDolSearchExtended::getObjectInstance($sObject);
  688. else if(in_array($sOperation, array('uninstall', 'disable')))
  689. BxDolSearchExtended::getObjectInstance($sObject)->clean();
  690. }
  691. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  692. }
  693. /**
  694. *
  695. * Process the list of transcoders provided in config array.
  696. * Transcoder objects to automatically register/unregister necessary alerts for.
  697. * @param string $sOperation - operation type.
  698. */
  699. protected function actionRegisterTranscoders($sOperation)
  700. {
  701. if(empty($this->_aConfig['transcoders']))
  702. return BX_DOL_STUDIO_INSTALLER_FAILED;
  703. BxDolTranscoderImage::registerHandlersArray($this->_aConfig['transcoders']);
  704. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  705. }
  706. /**
  707. *
  708. * Process the list of transcoders provided in config array.
  709. * Transcoder objects to automatically register/unregister necessary alerts for.
  710. * @param string $sOperation - operation type.
  711. */
  712. protected function actionUnregisterTranscoders($sOperation)
  713. {
  714. if(empty($this->_aConfig['transcoders']))
  715. return BX_DOL_STUDIO_INSTALLER_FAILED;
  716. BxDolTranscoderImage::unregisterHandlersArray($this->_aConfig['transcoders']);
  717. BxDolTranscoderImage::cleanupObjectsArray($this->_aConfig['transcoders']);
  718. return BX_DOL_STUDIO_INSTALLER_SUCCESS;
  719. }
  720. protected function actionClearDbCache($sOperation)
  721. {
  722. $oCache = $this->oDb->getDbCacheObject();
  723. $bResult = $oCache->removeAllByPrefix('db_');
  724. $bResult &= $this->oDb->cleanMemoryAll();
  725. $aKeys = array_keys($GLOBALS);
  726. $aKeysPrefixes = array('bx_dol_cache_memory_');
  727. foreach($aKeysPrefixes as $sKeyPrefix)
  728. foreach($aKeys as $sKey)
  729. if(substr($sKey, 0, strlen($sKeyPrefix)) == $sKeyPrefix)
  730. unset($GLOBALS[$sKey]);
  731. return $bResult ? BX_DOL_STUDIO_INSTALLER_SUCCESS : BX_DOL_STUDIO_INSTALLER_FAILED;
  732. }
  733. protected function _perform($sOperationName, $aParams = array())
  734. {
  735. $bHtmlResponce = isset($aParams['html_response']) && (bool)$aParams['html_response'];
  736. if(!defined('BX_SKIP_INSTALL_CHECK') && !defined('BX_DOL_CRON_EXECUTE') && !$GLOBALS['logged']['admin'])
  737. return array('message' => '_adm_mod_err_only_admin_can_perform_operations_with_modules', 'result' => false);
  738. $sMessage = '';
  739. foreach($this->_aConfig[$sOperationName] as $sAction => $iEnabled) {
  740. $sMethod = 'action' . bx_gen_method_name($sAction);
  741. if($iEnabled == 0 || !method_exists($this, $sMethod))
  742. continue;
  743. $mixedResult = $this->$sMethod($sOperationName);
  744. //--- On Success ---//
  745. if((is_int($mixedResult) && (int)$mixedResult == BX_DOL_STUDIO_INSTALLER_SUCCESS) || (isset($mixedResult['code']) && (int)$mixedResult['code'] == BX_DOL_STUDIO_INSTALLER_SUCCESS)) {
  746. $sMessage .= $this->_displayResult($sAction, true, isset($mixedResult['content']) ? $mixedResult['content'] : '', $bHtmlResponce);
  747. continue;
  748. }
  749. //--- On Failed ---//
  750. $sMethodFailed = $sMethod . 'Failed';
  751. return array('message' => $this->_displayResult($sAction, false, method_exists($this, $sMethodFailed) ? $this->$sMethodFailed($mixedResult) : $this->actionOperationFailed($mixedResult), $bHtmlResponce), 'result' => false);
  752. }
  753. if($this->_bShowOnSuccess)
  754. $sMessage = $this->_aActions['perform_' . $sOperationName]['success'] . $sMessage;
  755. return array('message' => $sMessage, 'result' => true);
  756. }
  757. protected function _displayResult($sAction, $bResult, $sResult = '', $bHtmlResponse = true)
  758. {
  759. if($bResult && !in_array($sAction, array('show_introduction', 'show_conclusion')) && !$this->_bShowOnSuccess)
  760. return '';
  761. $sTitle = $this->_aActions[$sAction]['title'] . ' ';
  762. if(!empty($sResult))
  763. $sResult = (substr($sResult, 0, 1) == '_' ? _t($sResult) : $sResult);
  764. $sContent = !empty($sResult) ? $sResult : _t($bResult ? '_adm_txt_modules_process_action_success' : '_adm_err_modules_process_action_failed');
  765. if(!$bHtmlResponse)
  766. return $sTitle . $sContent;
  767. return BxDolStudioTemplate::getInstance()->parseHtmlByName('mod_action_result_step.html', array(
  768. 'color' => $bResult ? 'green' : 'red',
  769. 'title' => $sTitle,
  770. 'content' => $sContent
  771. ));
  772. }
  773. protected function _getFileManager()
  774. {
  775. $oFile = null;
  776. if($this->_bUseFtp) {
  777. $oFile = new BxDolFtp(isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost', getParam('sys_ftp_login'), getParam('sys_ftp_password'), getParam('sys_ftp_dir'));
  778. if(!$oFile->connect())
  779. return null;
  780. if(!$oFile->isUna())
  781. return null;
  782. }
  783. else
  784. $oFile = BxDolFile::getInstance();
  785. return $oFile;
  786. }
  787. protected function _isCompatibleWith()
  788. {
  789. $sVersionCur = bx_get_ver();
  790. $bCompatible = false;
  791. if(isset($this->_aConfig['compatible_with']) && is_array($this->_aConfig['compatible_with']))
  792. foreach($this->_aConfig['compatible_with'] as $iKey => $sVersionReq)
  793. $bCompatible = $bCompatible || (version_compare($sVersionCur, $sVersionReq, '>=') == 1);
  794. return $bCompatible;
  795. }
  796. protected function filePathWithoutBase($sPath)
  797. {
  798. return bx_ltrim_str($sPath, $this->_sModulePath);
  799. }
  800. protected function getMarkersForDb()
  801. {
  802. return array(
  803. 'from' => array('{db_name}'),
  804. 'to' => array(defined('BX_DATABASE_NAME') ? BX_DATABASE_NAME : ''),
  805. );
  806. }
  807. protected function cleanupMemoryAfterAction($sModuleUri, $iModuleId)
  808. {
  809. $this->oDb->cleanMemory('sys_modules_' . $sModuleUri);
  810. $this->oDb->cleanMemory('sys_modules_' . $iModuleId);
  811. $this->oDb->cleanMemory('sys_modules');
  812. $this->oDb->cleanMemory('sys_modules_modules');
  813. $this->oDb->cleanMemory('sys_modules_modules_active');
  814. }
  815. }
  816. /** @} */