PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/components/bitrix/sale.crm.site.master/wizard/moduleinstallstep.php

https://gitlab.com/alexprowars/bitrix
PHP | 483 lines | 352 code | 71 blank | 60 comment | 41 complexity | b92417bfb49306328a621081bae4248d MD5 | raw file
  1. <?php
  2. namespace Bitrix\Sale\CrmSiteMaster\Steps;
  3. if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
  4. {
  5. die();
  6. }
  7. use Bitrix\Main,
  8. Bitrix\Main\Localization\Loc,
  9. Bitrix\Sale\CrmSiteMaster\Tools\ModuleChecker,
  10. Bitrix\Sale\CrmSiteMaster\Tools\PushChecker;
  11. Loc::loadMessages(__FILE__);
  12. /**
  13. * Class ModuleInstallStep
  14. * Install required modules
  15. *
  16. * @package Bitrix\Sale\CrmSiteMaster\Steps
  17. */
  18. class ModuleInstallStep extends \CWizardStep
  19. {
  20. private $currentStepName = __CLASS__;
  21. /** @var \SaleCrmSiteMaster */
  22. private $component = null;
  23. /** @var ModuleChecker */
  24. private $moduleChecker;
  25. /** @var array */
  26. private $modules = [];
  27. /**
  28. * Prepare next/prev buttons
  29. *
  30. * @throws \ReflectionException
  31. */
  32. private function prepareButtons()
  33. {
  34. $steps = $this->component->getSteps($this->currentStepName);
  35. $shortClassName = (new \ReflectionClass($this))->getShortName();
  36. if (isset($steps["NEXT_STEP"]))
  37. {
  38. $this->SetNextStep($steps["NEXT_STEP"]);
  39. $this->SetNextCaption(Loc::getMessage("SALE_CSM_WIZARD_".mb_strtoupper($shortClassName)."_NEXT"));
  40. }
  41. if (isset($steps["PREV_STEP"]))
  42. {
  43. $this->SetPrevStep($steps["PREV_STEP"]);
  44. $this->SetPrevCaption(Loc::getMessage("SALE_CSM_WIZARD_".mb_strtoupper($shortClassName)."_PREV"));
  45. }
  46. }
  47. /**
  48. * Initialization step id, title and next/prev step
  49. *
  50. * @throws \ReflectionException
  51. */
  52. public function initStep()
  53. {
  54. $this->component = $this->GetWizard()->GetVar("component");
  55. $this->moduleChecker = $this->component->getModuleChecker();
  56. $this->SetStepID($this->currentStepName);
  57. $this->SetTitle(Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_TITLE"));
  58. $this->prepareButtons();
  59. }
  60. /**
  61. * Show step content
  62. *
  63. * @return bool
  64. * @throws Main\ArgumentOutOfRangeException
  65. */
  66. public function showStep()
  67. {
  68. $wizard =& $this->GetWizard();
  69. if ($this->GetErrors())
  70. {
  71. return false;
  72. }
  73. $this->modules = $this->GetWizard()->GetVar("modules");
  74. $this->moduleChecker->setInstallStatus();
  75. ob_start();
  76. ?>
  77. <div class="adm-crm-site-master-progress-container" id="result">
  78. <div class="adm-crm-site-master-progress-counter">
  79. <div class="adm-crm-site-master-progress-container-num" id="progressBar_percent"></div>
  80. <div class="adm-crm-site-master-progress-container-per">%</div>
  81. </div>
  82. <img src="<?=$this->component->getPath()?>/wizard/images/install-complete-icon.svg" alt="" class="adm-crm-site-master-progress-complete">
  83. <div class="adm-crm-site-master-progress-complete-text">
  84. <?=Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_INSTALL_FINISH")?>
  85. </div>
  86. </div>
  87. <div class="adm-crm-site-master-progress">
  88. <div class="ui-progressbar ui-progressbar-lg ui-progressbar-success">
  89. <div class="ui-progressbar-track">
  90. <div class="ui-progressbar-bar" id="progressBar" style="width: 0%;"></div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="adm-crm-site-master-progress-description" id="progress_description">
  95. <?=Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_INSTALL_WAIT1")?><br>
  96. <?=Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_INSTALL_WAIT2")?>
  97. </div>
  98. <div class="adm-crm-slider-buttons" id="button_submit_wrap" style="display: none">
  99. <div class="ui-btn-container ui-btn-container-center">
  100. <button type="submit" class="ui-btn ui-btn-primary">
  101. <?=Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_NEXT")?>
  102. </button>
  103. </div>
  104. </div>
  105. <div id="error_container" style="display: none; margin-top: 25px">
  106. <div class="ui-alert ui-alert-danger ui-alert-inline ui-alert-icon-danger">
  107. <span class="ui-alert-message" id="error_text"></span>
  108. </div>
  109. <div class="adm-crm-slider-buttons" id="error_buttons">
  110. <div class="ui-btn-container ui-btn-container-center">
  111. <button type="button" id="error_retry_button" class="ui-btn ui-btn-primary" onclick="">
  112. <?=Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_RETRY_BUTTON")?>
  113. </button>
  114. </div>
  115. </div>
  116. </div>
  117. <?
  118. $modulesName = array_keys($this->modules);
  119. echo $this->ShowHiddenField("nextStep", $modulesName[0]);
  120. echo $this->ShowHiddenField("nextStepStage", "");
  121. ?><iframe style="display:none;" id="iframe-post-form" name="iframe-post-form" src="javascript:''"></iframe><?
  122. list($firstModule, $stage) = $this->getFirstModule();
  123. $formName = $wizard->GetFormName();
  124. $nextStepVarName = $wizard->GetRealName("nextStep");
  125. $messages = Loc::loadLanguageFile(__FILE__);
  126. ?>
  127. <script type="text/javascript">
  128. BX.message(<?=\CUtil::PhpToJSObject($messages)?>);
  129. var ajaxWizardForm = new CAjaxWizardForm("<?=$formName?>", "iframe-post-form", "<?=$nextStepVarName?>");
  130. ajaxWizardForm.Post("<?=$firstModule?>", "<?=$stage?>");
  131. </script>
  132. <?
  133. $content = ob_get_contents();
  134. ob_end_clean();
  135. $this->content = $content;
  136. return true;
  137. }
  138. /**
  139. * @return bool
  140. * @throws Main\ArgumentNullException
  141. * @throws Main\SystemException
  142. */
  143. public function onPostForm()
  144. {
  145. $wizard =& $this->GetWizard();
  146. if ($wizard->IsPrevButtonClick())
  147. {
  148. return false;
  149. }
  150. $this->modules = $this->GetWizard()->GetVar("modules");
  151. $moduleId = $wizard->GetVar("nextStep");
  152. $moduleStage = $wizard->GetVar("nextStepStage");
  153. if ($moduleId == "finish")
  154. {
  155. $modulesRequired = $wizard->GetVar("modulesRequired");
  156. $this->moduleChecker->setRequiredModules($modulesRequired);
  157. $checkModules = $this->moduleChecker->checkInstalledModules();
  158. if ($checkModules["NOT_INSTALL"])
  159. {
  160. $wizard->SetCurrentStep("Bitrix\Sale\CrmSiteMaster\Steps\ModuleStep");
  161. }
  162. else
  163. {
  164. $this->moduleChecker->deleteInstallStatus();
  165. $wizard->SetCurrentStep("Bitrix\Sale\CrmSiteMaster\Steps\SiteInstructionStep");
  166. }
  167. return true;
  168. }
  169. if ($moduleStage != "skip")
  170. {
  171. try
  172. {
  173. $this->installModule($moduleId);
  174. if ($moduleId === "pull")
  175. {
  176. $pushChecker = new PushChecker();
  177. $registerResult = $pushChecker->registerSharedServer();
  178. if (!$registerResult->isSuccess())
  179. {
  180. $this->SetError(implode("<br />", $registerResult->getErrorMessages()));
  181. }
  182. }
  183. }
  184. catch (\Exception $ex)
  185. {
  186. $this->SetError($ex->getMessage());
  187. }
  188. $cacheManager = Main\Application::getInstance()->getManagedCache();
  189. $cacheManager->clean("b_module");
  190. $cacheManager->clean("b_module_to_module");
  191. }
  192. if ($errors = $this->GetErrors())
  193. {
  194. $arError[] = Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_ERROR_OCCURED", [
  195. "#MODULE_NAME#" => $this->modules[$moduleId]["name"]
  196. ]);
  197. foreach ($errors as $error)
  198. {
  199. $arError[] = $error[0];
  200. }
  201. $strError = implode("<br />", $arError);
  202. $strError = addslashes(str_replace(["\r\n", "\r", "\n"], "<br />", $strError));
  203. $strError .= "<br /><br />".Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_ERROR_NOTICE", [
  204. "#MODULES_LINK#" => "/bitrix/admin/module_admin.php?lang=".LANGUAGE_ID
  205. ]);
  206. $response = "window.ajaxWizardForm.ShowError('".$strError."')";
  207. $this->sendResponse($response);
  208. }
  209. list($nextModule, $nextModuleStage, $stepsComplete) = $this->getModuleStep($moduleId);
  210. if ($nextModule == "finish")
  211. {
  212. $response = "window.ajaxWizardForm.StopAjax();";
  213. $response .= "window.ajaxWizardForm.SetStatus('100');";
  214. $response .= "window.ajaxWizardForm.Post('".$nextModule."', '".$nextModuleStage."');";
  215. }
  216. else
  217. {
  218. $percent = round($stepsComplete);
  219. $response = "window.ajaxWizardForm.SetStatus('".$percent."');";
  220. $response .= "window.ajaxWizardForm.Post('".$nextModule."', '".$nextModuleStage."');";
  221. }
  222. $this->sendResponse($response);
  223. return true;
  224. }
  225. /**
  226. * @return array
  227. */
  228. private function getFirstModule()
  229. {
  230. $modules = array_keys($this->modules);
  231. foreach ($modules as $module)
  232. {
  233. $stage = "";
  234. return [
  235. $module,
  236. $stage
  237. ];
  238. }
  239. return [
  240. "module_not_found",
  241. "finish"
  242. ];
  243. }
  244. /**
  245. * Get next module for installation
  246. *
  247. * @param $moduleId
  248. * @return array
  249. */
  250. private function getModuleStep($moduleId)
  251. {
  252. $modules = array_keys($this->modules);
  253. $nextService = $nextServiceStage = "finish";
  254. $key = array_search($moduleId, $modules);
  255. if ($key !== false)
  256. {
  257. if (isset($modules[$key+1]))
  258. {
  259. $nextService = $nextServiceStage = $modules[$key+1];
  260. }
  261. }
  262. if (!in_array($moduleId, $modules) || $nextService == "finish")
  263. {
  264. return [
  265. $nextService,
  266. $nextServiceStage,
  267. 100
  268. ];
  269. }
  270. $wizard =& $this->GetWizard();
  271. $nextServiceStage = "";
  272. $modulesCount = $wizard->GetVar("modulesCount");
  273. $stepsComplete = round((($key + 1) * 100) / $modulesCount);
  274. $wizard->SetVar("modules", $modules);
  275. return [
  276. $nextService,
  277. $nextServiceStage,
  278. $stepsComplete
  279. ];
  280. }
  281. /**
  282. * @param $moduleId
  283. */
  284. private function onModuleInstalledEvent($moduleId)
  285. {
  286. foreach (GetModuleEvents("main", "OnModuleInstalled", true) as $arEvent)
  287. {
  288. \ExecuteModuleEventEx($arEvent, array($moduleId));
  289. }
  290. }
  291. /**
  292. * Install required modules
  293. *
  294. * @param $moduleId
  295. * @return bool
  296. */
  297. private function installModule($moduleId)
  298. {
  299. /** @noinspection PhpVariableNamingConventionInspection */
  300. global $DB, $APPLICATION;
  301. if ($DB->type == "MYSQL" && defined("MYSQL_TABLE_TYPE") && MYSQL_TABLE_TYPE <> '')
  302. {
  303. $res = $DB->Query("SET storage_engine = '".MYSQL_TABLE_TYPE."'", true);
  304. if(!$res)
  305. {
  306. //mysql 5.7 removed storage_engine variable
  307. $DB->Query("SET default_storage_engine = '".MYSQL_TABLE_TYPE."'", true);
  308. }
  309. }
  310. $this->onModuleInstalledEvent($moduleId);
  311. if (!Main\ModuleManager::isModuleInstalled($moduleId))
  312. {
  313. @set_time_limit(3600);
  314. $module = \CModule::CreateModuleObject($moduleId);
  315. if (!is_object($module))
  316. {
  317. $this->SetError(Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_INSTALL_ERROR",
  318. ["#MODULE_NAME#" => $moduleId]
  319. ));
  320. return false;
  321. }
  322. if (method_exists($module, "CheckModules"))
  323. {
  324. $module->CheckModules();
  325. if ($ex = $APPLICATION->GetException())
  326. {
  327. $this->SetError($ex->GetString());
  328. return false;
  329. }
  330. }
  331. if (!$module->InstallDB())
  332. {
  333. if ($ex = $APPLICATION->GetException())
  334. {
  335. $this->SetError($ex->GetString());
  336. }
  337. return false;
  338. }
  339. $DB->RunSQLBatch(
  340. $_SERVER["DOCUMENT_ROOT"].'/bitrix/modules/'.$moduleId.'/install/db/'.mb_strtolower($DB->type).'/install.sql'
  341. );
  342. if ($this->checkModuleTables($moduleId) === false)
  343. {
  344. return false;
  345. }
  346. $module->InstallEvents();
  347. /** @noinspection PhpVoidFunctionResultUsedInspection */
  348. if (!$module->InstallFiles())
  349. {
  350. if ($ex = $APPLICATION->GetException())
  351. {
  352. $this->SetError($ex->GetString());
  353. }
  354. return false;
  355. }
  356. }
  357. return true;
  358. }
  359. /**
  360. * @param $module
  361. * @return bool
  362. */
  363. private function checkModuleTables($module)
  364. {
  365. /** @noinspection PhpVariableNamingConventionInspection */
  366. global $DB;
  367. $fileDb = $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/'.$module.'/install/db/mysql/install.sql';
  368. if (!file_exists($fileDb))
  369. $fileDb = $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/'.$module.'/install/mysql/install.sql';
  370. if (file_exists($fileDb))
  371. {
  372. $query = file_get_contents($fileDb);
  373. if ($query === false)
  374. {
  375. $this->SetError(Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_DB_FILE_ERROR", [
  376. "#FILE#" => $fileDb
  377. ]));
  378. return false;
  379. }
  380. $queryList = $DB->ParseSQLBatch(str_replace("\r", "", $query));
  381. foreach($queryList as $queryItem)
  382. {
  383. if (preg_match('#^(CREATE TABLE )(IF NOT EXISTS)? *`?([a-z0-9_]+)`?(.*);?$#mis', $queryItem, $regs))
  384. {
  385. $table = $regs[3];
  386. $bTableExists = $DB->Query('SHOW TABLES LIKE "'.$table.'"')->Fetch();
  387. if (!$bTableExists)
  388. {
  389. if (!$DB->Query($queryItem, true))
  390. {
  391. $this->SetError(Loc::getMessage("SALE_CSM_WIZARD_MODULEINSTALLSTEP_DB_TABLE_ERROR", [
  392. "#TABLE#" => $table
  393. ]));
  394. return false;
  395. }
  396. }
  397. }
  398. }
  399. }
  400. return true;
  401. }
  402. /**
  403. * @param $response
  404. */
  405. private function sendResponse($response)
  406. {
  407. /** @noinspection PhpVariableNamingConventionInspection */
  408. global $APPLICATION;
  409. $APPLICATION->RestartBuffer();
  410. die("[response]".$response."[/response]");
  411. }
  412. }