PageRenderTime 71ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/ModuleInstall/ModuleInstaller.php

https://github.com/BarnetikKoop/SuiteCRM
PHP | 2546 lines | 1987 code | 225 blank | 334 comment | 458 complexity | ea9d046088e06d216acdbccf520bc2de MD5 | raw file
Possible License(s): AGPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. <?php
  2. if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
  3. /*********************************************************************************
  4. * SugarCRM Community Edition is a customer relationship management program developed by
  5. * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
  6. * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd.
  7. * Copyright (C) 2011 - 2014 Salesagility Ltd.
  8. *
  9. * This program is free software; you can redistribute it and/or modify it under
  10. * the terms of the GNU Affero General Public License version 3 as published by the
  11. * Free Software Foundation with the addition of the following permission added
  12. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  13. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  14. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  15. *
  16. * This program is distributed in the hope that it will be useful, but WITHOUT
  17. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  18. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  19. * details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License along with
  22. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  23. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  24. * 02110-1301 USA.
  25. *
  26. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  27. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  28. *
  29. * The interactive user interfaces in modified source and object code versions
  30. * of this program must display Appropriate Legal Notices, as required under
  31. * Section 5 of the GNU Affero General Public License version 3.
  32. *
  33. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  34. * these Appropriate Legal Notices must retain the display of the "Powered by
  35. * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
  36. * reasonably feasible for technical reasons, the Appropriate Legal Notices must
  37. * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
  38. ********************************************************************************/
  39. /*
  40. * ModuleInstaller - takes an installation package from files in the custom/Extension/X directories, and moves them into custom/X to install them.
  41. * If a directory has multiple files they are concatenated together.
  42. * Relevant directories (X) are Layoutdefs, Vardefs, Include (bean stuff), Language, TableDictionary (relationships)
  43. *
  44. * Installation steps that involve more than just copying files:
  45. * 1. installing custom fields - calls bean->custom_fields->addField
  46. * 2. installing relationships - calls createTableParams to build the relationship table, and createRelationshipMeta to add the relationship to the relationship table
  47. * 3. rebuilding the relationships - at almost the last step in install(), calls modules/Administration/RebuildRelationship.php
  48. * 4. repair indices - uses "modules/Administration/RepairIndex.php";
  49. */
  50. require_once('include/utils/progress_bar_utils.php');
  51. require_once('ModuleInstall/ModuleScanner.php');
  52. define('DISABLED_PATH', 'Disabled');
  53. class ModuleInstaller{
  54. var $modules = array();
  55. var $silent = false;
  56. var $base_dir = '';
  57. var $modulesInPackage = array();
  58. public $disabled_path = DISABLED_PATH;
  59. public $id_name;
  60. function ModuleInstaller(){
  61. $this->ms = new ModuleScanner();
  62. $this->modules = get_module_dir_list();
  63. $this->db = & DBManagerFactory::getInstance();
  64. include("ModuleInstall/extensions.php");
  65. $this->extensions = $extensions;
  66. }
  67. /*
  68. * ModuleInstaller->install includes the manifest.php from the base directory it has been given. If it has been asked to do an upgrade it checks to see if there is
  69. * an upgrade_manifest defined in the manifest; if not it errors. It then adds the bean into the custom/Extension/application/Ext/Include/<module>.php - sets beanList, beanFiles
  70. * and moduleList - and then calls ModuleInstaller->merge_files('Ext/Include', 'modules.ext.php', '', true) to merge the individual module files into a combined file
  71. * /custom/Extension/application/Ext/Include/modules.ext.php (which now contains a list of all $beanList, $beanFiles and $moduleList for all extension modules) -
  72. * this file modules.ext.php is included at the end of modules.php.
  73. *
  74. * Finally it runs over a list of defined tasks; then install_beans, then install_custom_fields, then clear the Vardefs, run a RepairAndClear, then finally call rebuild_relationships.
  75. */
  76. function install($base_dir, $is_upgrade = false, $previous_version = ''){
  77. if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
  78. if ((defined('MODULE_INSTALLER_PACKAGE_SCAN') && MODULE_INSTALLER_PACKAGE_SCAN)
  79. || !empty($GLOBALS['sugar_config']['moduleInstaller']['packageScan'])) {
  80. $this->ms->scanPackage($base_dir);
  81. if($this->ms->hasIssues()){
  82. $this->ms->displayIssues();
  83. sugar_cleanup(true);
  84. }
  85. }
  86. // workaround for bug 45812 - refresh vardefs cache before unpacking to avoid partial vardefs in cache
  87. global $beanList;
  88. foreach ($this->modules as $module_name) {
  89. if (!empty($beanList[$module_name])) {
  90. $objectName = BeanFactory::getObjectName($module_name);
  91. VardefManager::loadVardef($module_name, $objectName);
  92. }
  93. }
  94. global $app_strings, $mod_strings;
  95. $this->base_dir = $base_dir;
  96. $total_steps = 5; //minimum number of steps with no tasks
  97. $current_step = 0;
  98. $tasks = array(
  99. 'pre_execute',
  100. 'install_copy',
  101. 'install_extensions',
  102. 'install_images',
  103. 'install_dcactions',
  104. 'install_dashlets',
  105. 'install_connectors',
  106. 'install_layoutfields',
  107. 'install_relationships',
  108. 'enable_manifest_logichooks',
  109. 'post_execute',
  110. 'reset_opcodes',
  111. );
  112. $total_steps += count($tasks);
  113. if(file_exists($this->base_dir . '/manifest.php')){
  114. if(!$this->silent){
  115. $current_step++;
  116. display_progress_bar('install', $current_step, $total_steps);
  117. echo '<div id ="displayLoglink" ><a href="#" onclick="document.getElementById(\'displayLog\').style.display=\'\'">'
  118. .$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
  119. }
  120. include($this->base_dir . '/manifest.php');
  121. if($is_upgrade && !empty($previous_version)){
  122. //check if the upgrade path exists
  123. if(!empty($upgrade_manifest)){
  124. if(!empty($upgrade_manifest['upgrade_paths'])){
  125. if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
  126. $installdefs = $upgrade_manifest['upgrade_paths'][$previous_version];
  127. }else{
  128. $errors[] = 'No Upgrade Path Found in manifest.';
  129. $this->abort($errors);
  130. }//fi
  131. }//fi
  132. }//fi
  133. }//fi
  134. $this->id_name = $installdefs['id'];
  135. $this->installdefs = $installdefs;
  136. if(!$this->silent){
  137. $current_step++;
  138. update_progress_bar('install', $current_step, $total_steps);
  139. }
  140. foreach($tasks as $task){
  141. $this->$task();
  142. if(!$this->silent){
  143. $current_step++;
  144. update_progress_bar('install', $current_step, $total_steps);
  145. }
  146. }
  147. $this->install_beans($this->installed_modules);
  148. if(!$this->silent){
  149. $current_step++;
  150. update_progress_bar('install', $total_steps, $total_steps);
  151. }
  152. if(isset($installdefs['custom_fields'])){
  153. $this->log(translate('LBL_MI_IN_CUSTOMFIELD'));
  154. $this->install_custom_fields($installdefs['custom_fields']);
  155. }
  156. if(!$this->silent){
  157. $current_step++;
  158. update_progress_bar('install', $current_step, $total_steps);
  159. echo '</div>';
  160. }
  161. if(!$this->silent){
  162. $current_step++;
  163. update_progress_bar('install', $current_step, $total_steps);
  164. echo '</div>';
  165. }
  166. $selectedActions = array(
  167. 'clearTpls',
  168. 'clearJsFiles',
  169. 'clearDashlets',
  170. 'clearVardefs',
  171. 'clearJsLangFiles',
  172. 'rebuildAuditTables',
  173. 'repairDatabase',
  174. );
  175. VardefManager::clearVardef();
  176. global $beanList, $beanFiles, $moduleList;
  177. if (file_exists('custom/application/Ext/Include/modules.ext.php'))
  178. {
  179. include('custom/application/Ext/Include/modules.ext.php');
  180. }
  181. require_once("modules/Administration/upgrade_custom_relationships.php");
  182. upgrade_custom_relationships($this->installed_modules);
  183. $this->rebuild_all(true);
  184. require_once('modules/Administration/QuickRepairAndRebuild.php');
  185. $rac = new RepairAndClear();
  186. $rac->repairAndClearAll($selectedActions, $this->installed_modules,true, false);
  187. $this->rebuild_relationships();
  188. UpdateSystemTabs('Add',$this->tab_modules);
  189. //Clear out all the langauge cache files.
  190. clearAllJsAndJsLangFilesWithoutOutput();
  191. $cache_key = 'app_list_strings.'.$GLOBALS['current_language'];
  192. sugar_cache_clear($cache_key );
  193. sugar_cache_reset();
  194. //clear the unified_search_module.php file
  195. require_once('modules/Home/UnifiedSearchAdvanced.php');
  196. UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
  197. $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
  198. }else{
  199. die("No \$installdefs Defined In $this->base_dir/manifest.php");
  200. }
  201. }
  202. function install_user_prefs($module, $hide_from_user=false){
  203. UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, !$hide_from_user);
  204. UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, $hide_from_user);
  205. UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, $hide_from_user);
  206. }
  207. function uninstall_user_prefs($module){
  208. UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, true);
  209. UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, true);
  210. UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, true);
  211. }
  212. function pre_execute(){
  213. require_once($this->base_dir . '/manifest.php');
  214. if(isset($this->installdefs['pre_execute']) && is_array($this->installdefs['pre_execute'])){
  215. foreach($this->installdefs['pre_execute'] as $includefile){
  216. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  217. }
  218. }
  219. }
  220. function post_execute(){
  221. require_once($this->base_dir . '/manifest.php');
  222. if(isset($this->installdefs['post_execute']) && is_array($this->installdefs['post_execute'])){
  223. foreach($this->installdefs['post_execute'] as $includefile){
  224. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  225. }
  226. }
  227. }
  228. function pre_uninstall(){
  229. require_once($this->base_dir . '/manifest.php');
  230. if(isset($this->installdefs['pre_uninstall']) && is_array($this->installdefs['pre_uninstall'])){
  231. foreach($this->installdefs['pre_uninstall'] as $includefile){
  232. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  233. }
  234. }
  235. }
  236. function post_uninstall(){
  237. require_once($this->base_dir . '/manifest.php');
  238. if(isset($this->installdefs['post_uninstall']) && is_array($this->installdefs['post_uninstall'])){
  239. foreach($this->installdefs['post_uninstall'] as $includefile){
  240. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  241. }
  242. }
  243. }
  244. /*
  245. * ModuleInstaller->install_copy gets the copy section of installdefs in the manifest and calls copy_path to copy each path (file or directory) to its final location
  246. * (specified as from and to in the manifest), replacing <basepath> by the base_dir value passed in to install.
  247. */
  248. function install_copy(){
  249. if(isset($this->installdefs['copy'])){
  250. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
  251. $backup_path = clean_path( remove_file_extension(urldecode($_REQUEST['install_file']))."-restore" );
  252. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  253. foreach($this->installdefs['copy'] as $cp){
  254. $GLOBALS['log']->debug("Copying ..." . $cp['from']. " to " .$cp['to'] );
  255. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
  256. //$this->copy_path($cp['from'], $cp['to']);
  257. $this->copy_path($cp['from'], $cp['to'], $backup_path);
  258. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  259. }
  260. //here we should get the module list again as we could have copied something to the modules dir
  261. $this->modules = get_module_dir_list();
  262. }
  263. }
  264. function uninstall_copy(){
  265. if(!empty($this->installdefs['copy'])){
  266. foreach($this->installdefs['copy'] as $cp){
  267. $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
  268. $cp['from'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['from']));
  269. $GLOBALS['log']->debug('Unlink ' . $cp['to']);
  270. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
  271. //rmdir_recursive($cp['to']);
  272. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
  273. $this->uninstall_new_files($cp, $backup_path);
  274. $this->copy_path($backup_path, $cp['to'], $backup_path, true);
  275. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  276. }
  277. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore");
  278. if(file_exists($backup_path))
  279. rmdir_recursive($backup_path);
  280. }
  281. }
  282. /**
  283. * Removes any files that were added by the loaded module. If the files already existed prior to install
  284. * it will be handled by copy_path with the uninstall parameter.
  285. *
  286. */
  287. function uninstall_new_files($cp, $backup_path){
  288. $zip_files = $this->dir_get_files($cp['from'],$cp['from']);
  289. $backup_files = $this->dir_get_files($backup_path, $backup_path);
  290. foreach($zip_files as $k=>$v){
  291. //if it's not a backup then it is probably a new file but we'll check that it is not in the md5.files first
  292. if(!isset($backup_files[$k])){
  293. $to = $cp['to'] . $k;
  294. //if it's not a sugar file then we remove it otherwise we can't restor it
  295. if(!$this->ms->sugarFileExists($to)){
  296. $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting file ' . $to);
  297. if(file_exists($to)) {
  298. unlink($to);
  299. }
  300. }else{
  301. $GLOBALS['log']->fatal('ModuleInstaller[uninstall_new_file] Could not remove file ' . $to . ' as no backup file was found to restore to');
  302. }
  303. }
  304. }
  305. //lets check if the directory is empty if it is we will delete it as well
  306. $files_remaining = $this->dir_file_count($cp['to']);
  307. if(file_exists($cp['to']) && $files_remaining == 0){
  308. $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting directory ' . $cp['to']);
  309. rmdir_recursive($cp['to']);
  310. }
  311. }
  312. /**
  313. * Get directory where module's extensions go
  314. * @param string $module Module name
  315. */
  316. public function getExtDir($module)
  317. {
  318. if($module == 'application') {
  319. return "custom/Extension/application/Ext";
  320. } else {
  321. return "custom/Extension/modules/$module/Ext";
  322. }
  323. }
  324. /**
  325. * Install file(s) into Ext/ part
  326. * @param string $section Name of the install file section
  327. * @param string $extname Name in Ext directory
  328. * @param string $module This extension belongs to a specific module
  329. */
  330. public function installExt($section, $extname, $module = '')
  331. {
  332. if(isset($this->installdefs[$section])){
  333. $this->log(sprintf(translate("LBL_MI_IN_EXT"), $section));
  334. foreach($this->installdefs[$section] as $item){
  335. if(isset($item['from'])) {
  336. $from = str_replace('<basepath>', $this->base_dir, $item['from']);
  337. } else {
  338. $from = '';
  339. }
  340. if(!empty($module)) {
  341. $item['to_module'] = $module;
  342. }
  343. $GLOBALS['log']->debug("Installing section $section from $from for " .$item['to_module'] );
  344. if($item['to_module'] == 'application') {
  345. $path = "custom/Extension/application/Ext/$extname";
  346. } else {
  347. $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
  348. }
  349. if(!file_exists($path)){
  350. mkdir_recursive($path, true);
  351. }
  352. if(isset($item["name"])) {
  353. $target = $item["name"];
  354. } else if (!empty($from)){
  355. $target = basename($from, ".php");
  356. } else {
  357. $target = $this->id_name;
  358. }
  359. if(!empty($from)) {
  360. copy_recursive($from , "$path/$target.php");
  361. }
  362. }
  363. }
  364. }
  365. /**
  366. * Uninstall file(s) into Ext/ part
  367. * @param string $section Name of the install file section
  368. * @param string $extname Name in Ext directory
  369. * @param string $module This extension belongs to a specific module
  370. */
  371. public function uninstallExt($section, $extname, $module = '')
  372. {
  373. if(isset($this->installdefs[$section])){
  374. $this->log(sprintf(translate("LBL_MI_UN_EXT"), $section));
  375. foreach($this->installdefs[$section] as $item){
  376. if(isset($item['from'])) {
  377. $from = str_replace('<basepath>', $this->base_dir, $item['from']);
  378. } else {
  379. $from = '';
  380. }
  381. if(!empty($module)) {
  382. $item['to_module'] = $module;
  383. }
  384. $GLOBALS['log']->debug("Uninstalling section $section from $from for " .$item['to_module'] );
  385. if($item['to_module'] == 'application') {
  386. $path = "custom/Extension/application/Ext/$extname";
  387. } else {
  388. $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
  389. }
  390. if(isset($item["name"])) {
  391. $target = $item["name"];
  392. } else if (!empty($from)){
  393. $target = basename($from, ".php");
  394. } else {
  395. $target = $this->id_name;
  396. }
  397. $disabled_path = $path.'/'.DISABLED_PATH;
  398. if (file_exists("$path/$target.php")) {
  399. rmdir_recursive("$path/$target.php");
  400. } else if (file_exists("$disabled_path/$target.php")) {
  401. rmdir_recursive("$disabled_path/$target.php");
  402. } else if (!empty($from) && file_exists($path . '/'. basename($from))) {
  403. rmdir_recursive( $path . '/'. basename($from));
  404. } else if (!empty($from) && file_exists($disabled_path . '/'. basename($from))) {
  405. rmdir_recursive( $disabled_path . '/'. basename($from));
  406. }
  407. }
  408. }
  409. }
  410. /**
  411. * Rebuild generic extension
  412. * @param string $ext Extension directory
  413. * @param string $filename Target filename
  414. */
  415. public function rebuildExt($ext, $filename)
  416. {
  417. $this->log(translate('LBL_MI_REBUILDING') . " $ext...");
  418. $this->merge_files("Ext/$ext/", $filename);
  419. }
  420. /**
  421. * Disable generic extension
  422. * @param string $section Install file section name
  423. * @param string $extname Extension directory
  424. * @param string $module This extension belongs to a specific module
  425. */
  426. public function disableExt($section, $extname, $module = '')
  427. {
  428. if(isset($this->installdefs[$section])) {
  429. foreach($this->installdefs[$section] as $item) {
  430. if(isset($item['from'])) {
  431. $from = str_replace('<basepath>', $this->base_dir, $item['from']);
  432. } else {
  433. $from = '';
  434. }
  435. if(!empty($module)) {
  436. $item['to_module'] = $module;
  437. }
  438. $GLOBALS['log']->debug("Disabling $extname ... from $from for " .$item['to_module']);
  439. if($item['to_module'] == 'application') {
  440. $path = "custom/Extension/application/Ext/$extname";
  441. } else {
  442. $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
  443. }
  444. if(isset($item["name"])) {
  445. $target = $item["name"];
  446. } else if (!empty($from)){
  447. $target = basename($from, ".php");
  448. }else {
  449. $target = $this->id_name;
  450. }
  451. $disabled_path = $path.'/'.DISABLED_PATH;
  452. if (file_exists("$path/$target.php")) {
  453. mkdir_recursive($disabled_path, true);
  454. rename("$path/$target.php", "$disabled_path/$target.php");
  455. } else if (!empty($from) && file_exists($path . '/'. basename($from))) {
  456. mkdir_recursive($disabled_path, true);
  457. rename( $path . '/'. basename($from), $disabled_path.'/'. basename($from));
  458. }
  459. }
  460. }
  461. }
  462. /**
  463. * Enable generic extension
  464. * @param string $section Install file section name
  465. * @param string $extname Extension directory
  466. * @param string $module This extension belongs to a specific module
  467. */
  468. public function enableExt($section, $extname, $module = '')
  469. {
  470. if(isset($this->installdefs[$section])) {
  471. foreach($this->installdefs[$section] as $item) {
  472. if(isset($item['from'])) {
  473. $from = str_replace('<basepath>', $this->base_dir, $item['from']);
  474. } else {
  475. $from = '';
  476. }
  477. if(!empty($module)) {
  478. $item['to_module'] = $module;
  479. }
  480. $GLOBALS['log']->debug("Enabling $extname ... from $from for " .$item['to_module']);
  481. if($item['to_module'] == 'application') {
  482. $path = "custom/Extension/application/Ext/$extname";
  483. } else {
  484. $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname";
  485. }
  486. if(isset($item["name"])) {
  487. $target = $item["name"];
  488. } else if (!empty($from)){
  489. $target = basename($from, ".php");
  490. } else {
  491. $target = $this->id_name;
  492. }
  493. if(!file_exists($path)) {
  494. mkdir_recursive($path, true);
  495. }
  496. $disabled_path = $path.'/'.DISABLED_PATH;
  497. if (file_exists("$disabled_path/$target.php")) {
  498. rename("$disabled_path/$target.php", "$path/$target.php");
  499. }
  500. if (!empty($from) && file_exists($disabled_path . '/'. basename($from))) {
  501. rename($disabled_path.'/'. basename($from), $path . '/'. basename($from));
  502. }
  503. }
  504. }
  505. }
  506. /**
  507. * Method removes module from global search configurations
  508. *
  509. * return bool
  510. */
  511. public function uninstall_global_search()
  512. {
  513. if (empty($this->installdefs['beans']))
  514. {
  515. return true;
  516. }
  517. if (is_file('custom/modules/unified_search_modules_display.php') == false)
  518. {
  519. return true;
  520. }
  521. $user = new User();
  522. $users = get_user_array();
  523. $unified_search_modules_display = array();
  524. require('custom/modules/unified_search_modules_display.php');
  525. foreach($this->installdefs['beans'] as $beanDefs)
  526. {
  527. if (array_key_exists($beanDefs['module'], $unified_search_modules_display) == false)
  528. {
  529. continue;
  530. }
  531. unset($unified_search_modules_display[$beanDefs['module']]);
  532. foreach($users as $userId => $userName)
  533. {
  534. if (empty($userId))
  535. {
  536. continue;
  537. }
  538. $user->retrieve($userId);
  539. $prefs = $user->getPreference('globalSearch', 'search');
  540. if (array_key_exists($beanDefs['module'], $prefs) == false)
  541. {
  542. continue;
  543. }
  544. unset($prefs[$beanDefs['module']]);
  545. $user->setPreference('globalSearch', $prefs, 0, 'search');
  546. $user->savePreferencesToDB();
  547. }
  548. }
  549. if (write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php') == false)
  550. {
  551. global $app_strings;
  552. $msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
  553. $GLOBALS['log']->error($msg);
  554. throw new Exception($msg);
  555. return false;
  556. }
  557. return true;
  558. }
  559. /**
  560. * Method enables module in global search configurations by disabled_module_visible key
  561. *
  562. * return bool
  563. */
  564. public function enable_global_search()
  565. {
  566. if (empty($this->installdefs['beans']))
  567. {
  568. return true;
  569. }
  570. if (is_file('custom/modules/unified_search_modules_display.php') == false)
  571. {
  572. return true;
  573. }
  574. $unified_search_modules_display = array();
  575. require('custom/modules/unified_search_modules_display.php');
  576. foreach($this->installdefs['beans'] as $beanDefs)
  577. {
  578. if (array_key_exists($beanDefs['module'], $unified_search_modules_display) == false)
  579. {
  580. continue;
  581. }
  582. if (isset($unified_search_modules_display[$beanDefs['module']]['disabled_module_visible']) == false)
  583. {
  584. continue;
  585. }
  586. $unified_search_modules_display[$beanDefs['module']]['visible'] = $unified_search_modules_display[$beanDefs['module']]['disabled_module_visible'];
  587. unset($unified_search_modules_display[$beanDefs['module']]['disabled_module_visible']);
  588. }
  589. if (write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php') == false)
  590. {
  591. global $app_strings;
  592. $msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
  593. $GLOBALS['log']->error($msg);
  594. throw new Exception($msg);
  595. return false;
  596. }
  597. return true;
  598. }
  599. /**
  600. * Method disables module in global search configurations by disabled_module_visible key
  601. *
  602. * return bool
  603. */
  604. public function disable_global_search()
  605. {
  606. if (empty($this->installdefs['beans']))
  607. {
  608. return true;
  609. }
  610. if (is_file('custom/modules/unified_search_modules_display.php') == false)
  611. {
  612. return true;
  613. }
  614. $unified_search_modules_display = array();
  615. require('custom/modules/unified_search_modules_display.php');
  616. foreach($this->installdefs['beans'] as $beanDefs)
  617. {
  618. if (array_key_exists($beanDefs['module'], $unified_search_modules_display) == false)
  619. {
  620. continue;
  621. }
  622. if (isset($unified_search_modules_display[$beanDefs['module']]['visible']) == false)
  623. {
  624. continue;
  625. }
  626. $unified_search_modules_display[$beanDefs['module']]['disabled_module_visible'] = $unified_search_modules_display[$beanDefs['module']]['visible'];
  627. $unified_search_modules_display[$beanDefs['module']]['visible'] = false;
  628. }
  629. if (write_array_to_file("unified_search_modules_display", $unified_search_modules_display, 'custom/modules/unified_search_modules_display.php') == false)
  630. {
  631. global $app_strings;
  632. $msg = string_format($app_strings['ERR_FILE_WRITE'], array('custom/modules/unified_search_modules_display.php'));
  633. $GLOBALS['log']->error($msg);
  634. throw new Exception($msg);
  635. return false;
  636. }
  637. return true;
  638. }
  639. public function install_extensions()
  640. {
  641. foreach($this->extensions as $extname => $ext) {
  642. $install = "install_$extname";
  643. if(method_exists($this, $install)) {
  644. // non-standard function
  645. $this->$install();
  646. } else {
  647. if(!empty($ext["section"])) {
  648. $module = isset($ext['module'])?$ext['module']:'';
  649. $this->installExt($ext["section"], $ext["extdir"], $module);
  650. }
  651. }
  652. }
  653. $this->rebuild_extensions();
  654. }
  655. public function uninstall_extensions()
  656. {
  657. foreach($this->extensions as $extname => $ext) {
  658. $func = "uninstall_$extname";
  659. if(method_exists($this, $func)) {
  660. // non-standard function
  661. $this->$func();
  662. } else {
  663. if(!empty($ext["section"])) {
  664. $module = isset($ext['module'])?$ext['module']:'';
  665. $this->uninstallExt($ext["section"], $ext["extdir"], $module);
  666. }
  667. }
  668. }
  669. $this->rebuild_extensions();
  670. }
  671. public function rebuild_extensions()
  672. {
  673. foreach($this->extensions as $extname => $ext) {
  674. $func = "rebuild_$extname";
  675. if(method_exists($this, $func)) {
  676. // non-standard function
  677. $this->$func();
  678. } else {
  679. $this->rebuildExt($ext["extdir"], $ext["file"]);
  680. }
  681. }
  682. }
  683. public function disable_extensions()
  684. {
  685. foreach($this->extensions as $extname => $ext) {
  686. $func = "disable_$extname";
  687. if(method_exists($this, $func)) {
  688. // non-standard install
  689. $this->$func();
  690. } else {
  691. if(!empty($ext["section"])) {
  692. $module = isset($ext['module'])?$ext['module']:'';
  693. $this->disableExt($ext["section"], $ext["extdir"], $module);
  694. }
  695. }
  696. }
  697. $this->rebuild_extensions();
  698. }
  699. public function enable_extensions()
  700. {
  701. foreach($this->extensions as $extname => $ext) {
  702. $func = "enable_$extname";
  703. if(method_exists($this, $func)) {
  704. // non-standard install
  705. $this->$func();
  706. } else {
  707. if(!empty($ext["section"])) {
  708. $module = isset($ext['module'])?$ext['module']:'';
  709. $this->enableExt($ext["section"], $ext["extdir"], $module);
  710. }
  711. }
  712. }
  713. $this->rebuild_extensions();
  714. }
  715. function install_dashlets()
  716. {
  717. if(isset($this->installdefs['dashlets'])){
  718. foreach($this->installdefs['dashlets'] as $cp){
  719. $this->log(translate('LBL_MI_IN_DASHLETS') . $cp['name']);
  720. $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
  721. $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
  722. $GLOBALS['log']->debug("Installing Dashlet " . $cp['name'] . "..." . $cp['from'] );
  723. if(!file_exists($path)){
  724. mkdir_recursive($path, true);
  725. }
  726. copy_recursive($cp['from'] , $path);
  727. }
  728. include('modules/Administration/RebuildDashlets.php');
  729. }
  730. }
  731. function uninstall_dashlets(){
  732. if(isset($this->installdefs['dashlets'])){
  733. foreach($this->installdefs['dashlets'] as $cp){
  734. $this->log(translate('LBL_MI_UN_DASHLETS') . $cp['name']);
  735. $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
  736. $GLOBALS['log']->debug('Unlink ' .$path);
  737. if (file_exists($path))
  738. rmdir_recursive($path);
  739. }
  740. include('modules/Administration/RebuildDashlets.php');
  741. }
  742. }
  743. function install_images(){
  744. if(isset($this->installdefs['image_dir'])){
  745. $this->log( translate('LBL_MI_IN_IMAGES') );
  746. $this->copy_path($this->installdefs['image_dir'] , 'custom/themes');
  747. }
  748. }
  749. function install_dcactions(){
  750. if(isset($this->installdefs['dcaction'])){
  751. $this->log(translate('LBL_MI_IN_MENUS'));
  752. foreach($this->installdefs['dcaction'] as $action){
  753. $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
  754. $GLOBALS['log']->debug("Installing DCActions ..." . $action['from']);
  755. $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
  756. if(!file_exists($path)){
  757. mkdir_recursive($path, true);
  758. }
  759. copy_recursive($action['from'] , $path . '/'. $this->id_name . '.php');
  760. }
  761. $this->rebuild_dashletcontainers();
  762. }
  763. }
  764. function uninstall_dcactions(){
  765. if(isset($this->installdefs['dcaction'])){
  766. $this->log(translate('LBL_MI_UN_MENUS'));
  767. foreach($this->installdefs['dcaction'] as $action){
  768. $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
  769. $GLOBALS['log']->debug("Uninstalling DCActions ..." . $action['from'] );
  770. $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
  771. if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
  772. {
  773. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  774. }
  775. else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
  776. {
  777. rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
  778. }
  779. }
  780. $this->rebuild_dashletcontainers();
  781. }
  782. }
  783. function install_connectors(){
  784. if(isset($this->installdefs['connectors'])){
  785. foreach($this->installdefs['connectors'] as $cp){
  786. $this->log(translate('LBL_MI_IN_CONNECTORS') . $cp['name']);
  787. $dir = str_replace('_','/',$cp['name']);
  788. $cp['connector'] = str_replace('<basepath>', $this->base_dir, $cp['connector']);
  789. $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir. '/';
  790. $GLOBALS['log']->debug("Installing Connector " . $cp['name'] . "..." . $cp['connector'] );
  791. if(!file_exists($source_path)){
  792. mkdir_recursive($source_path, true);
  793. }
  794. copy_recursive($cp['connector'] , $source_path);
  795. //Install optional formatter code if it is specified
  796. if(!empty($cp['formatter'])) {
  797. $cp['formatter'] = str_replace('<basepath>', $this->base_dir, $cp['formatter']);
  798. $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir. '/';
  799. if(!file_exists($formatter_path)){
  800. mkdir_recursive($formatter_path, true);
  801. }
  802. copy_recursive($cp['formatter'] , $formatter_path);
  803. }
  804. }
  805. require_once('include/connectors/utils/ConnectorUtils.php');
  806. ConnectorUtils::installSource($cp['name']);
  807. }
  808. }
  809. function uninstall_connectors(){
  810. if(isset($this->installdefs['connectors'])){
  811. foreach($this->installdefs['connectors'] as $cp){
  812. $this->log(translate('LBL_MI_UN_CONNECTORS') . $cp['name']);
  813. $dir = str_replace('_','/',$cp['name']);
  814. $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir;
  815. $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir;
  816. $GLOBALS['log']->debug('Unlink ' .$source_path);
  817. rmdir_recursive($source_path);
  818. rmdir_recursive($formatter_path);
  819. }
  820. require_once('include/connectors/utils/ConnectorUtils.php');
  821. //ConnectorUtils::getConnectors(true);
  822. ConnectorUtils::uninstallSource($cp['name']);
  823. }
  824. }
  825. function install_vardef($from, $to_module)
  826. {
  827. $GLOBALS['log']->debug("Installing Vardefs ..." . $from . " for " .$to_module);
  828. $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs';
  829. if($to_module == 'application'){
  830. $path ='custom/Extension/' . $to_module. '/Ext/Vardefs';
  831. }
  832. if(!file_exists($path)){
  833. mkdir_recursive($path, true);
  834. }
  835. copy_recursive($from , $path.'/'. basename($from));
  836. }
  837. function install_layoutdef($from, $to_module){
  838. $GLOBALS['log']->debug("Installing Layout Defs ..." . $from . " for " .$to_module);
  839. $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs';
  840. if($to_module == 'application'){
  841. $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs';
  842. }
  843. if(!file_exists($path)){
  844. mkdir_recursive($path, true);
  845. }
  846. copy_recursive($from , $path.'/'. basename($from));
  847. }
  848. // Non-standard - needs special rebuild call
  849. function install_languages()
  850. {
  851. $languages = array();
  852. if(isset($this->installdefs['language']))
  853. {
  854. $this->log(translate('LBL_MI_IN_LANG') );
  855. foreach($this->installdefs['language'] as $packs)
  856. {
  857. $modules[]=$packs['to_module'];
  858. $languages[$packs['language']] = $packs['language'];
  859. $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
  860. $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
  861. $path = $this->getInstallLanguagesPath($packs);
  862. if (!file_exists(dirname($path))) {
  863. mkdir_recursive(dirname($path), true);
  864. }
  865. copy_recursive($packs['from'], $path);
  866. }
  867. $this->rebuild_languages($languages, $modules);
  868. }
  869. }
  870. /**
  871. * Function return path to file where store label
  872. *
  873. * @param $packs
  874. * @return string
  875. */
  876. protected function getInstallLanguagesPath($packs)
  877. {
  878. $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
  879. if($packs['to_module'] == 'application'){
  880. $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
  881. }
  882. $path .= '/'.$packs['language'].'.'. $this->id_name . '.php';
  883. return $path;
  884. }
  885. // Non-standard, needs special rebuild
  886. function uninstall_languages(){
  887. $languages = array();
  888. if(isset($this->installdefs['language'])){
  889. $this->log(translate('LBL_MI_UN_LANG') );
  890. foreach($this->installdefs['language'] as $packs){
  891. $modules[]=$packs['to_module'];
  892. $languages[$packs['language']] = $packs['language'];
  893. $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
  894. $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
  895. $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
  896. if($packs['to_module'] == 'application'){
  897. $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
  898. }
  899. if (sugar_is_file($path.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
  900. rmdir_recursive( $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
  901. } else if (sugar_is_file($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
  902. rmdir_recursive($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w');
  903. }
  904. }
  905. $this->rebuild_languages($languages, $modules);
  906. }
  907. }
  908. // Non-standard, needs special rebuild
  909. public function disable_languages()
  910. {
  911. if(isset($this->installdefs['language'])) {
  912. $languages = $modules = array();
  913. foreach($this->installdefs['language'] as $item) {
  914. $from = str_replace('<basepath>', $this->base_dir, $item['from']);
  915. $GLOBALS['log']->debug("Disabling Language {$item['language']}... from $from for " .$item['to_module']);
  916. $modules[]=$item['to_module'];
  917. $languages[$item['language']] = $item['language'];
  918. if($item['to_module'] == 'application') {
  919. $path = "custom/Extension/application/Ext/Language";
  920. } else {
  921. $path = "custom/Extension/modules/{$item['to_module']}/Ext/Language";
  922. }
  923. if(isset($item["name"])) {
  924. $target = $item["name"];
  925. } else {
  926. $target = $this->id_name;
  927. }
  928. $target = "{$item['language']}.$target";
  929. $disabled_path = $path.'/'.DISABLED_PATH;
  930. if (file_exists("$path/$target.php")) {
  931. mkdir_recursive($disabled_path, true);
  932. rename("$path/$target.php", "$disabled_path/$target.php");
  933. } else if (file_exists($path . '/'. basename($from))) {
  934. mkdir_recursive($disabled_path, true);
  935. rename( $path . '/'. basename($from), $disabled_path.'/'. basename($from));
  936. }
  937. }
  938. $this->rebuild_languages($languages, $modules);
  939. }
  940. }
  941. // Non-standard, needs special rebuild
  942. public function enable_languages()
  943. {
  944. if(isset($this->installdefs['language'])) {
  945. foreach($this->installdefs['language'] as $item) {
  946. $from = str_replace('<basepath>', $this->base_dir, $item['from']);
  947. $GLOBALS['log']->debug("Enabling Language {$item['language']}... from $from for " .$item['to_module']);
  948. $modules[]=$item['to_module'];
  949. $languages[$item['language']] = $item['language'];
  950. if(!empty($module)) {
  951. $item['to_module'] = $module;
  952. }
  953. if($item['to_module'] == 'application') {
  954. $path = "custom/Extension/application/Ext/Language";
  955. } else {
  956. $path = "custom/Extension/modules/{$item['to_module']}/Ext/Language";
  957. }
  958. if(isset($item["name"])) {
  959. $target = $item["name"];
  960. } else {
  961. $target = $this->id_name;
  962. }
  963. $target = "{$item['language']}.$target";
  964. if(!file_exists($path)) {
  965. mkdir_recursive($path, true);
  966. }
  967. $disabled_path = $path.'/'.DISABLED_PATH;
  968. if (file_exists("$disabled_path/$target.php")) {
  969. rename("$disabled_path/$target.php", "$path/$target.php");
  970. }
  971. if (file_exists($disabled_path . '/'. basename($from))) {
  972. rename($disabled_path.'/'. basename($from), $path . '/'. basename($from));
  973. }
  974. }
  975. $this->rebuild_languages($languages, $modules);
  976. }
  977. }
  978. // Functions for adding and removing logic hooks from uploaded files
  979. // Since one class/file can be used by multiple logic hooks, I'm not going to touch the file labeled in the logic_hook entry
  980. /* The module hook definition should look like this:
  981. $installdefs = array(
  982. ... blah blah ...
  983. 'logic_hooks' => array(
  984. array('module' => 'Accounts',
  985. 'hook' => 'after_save',
  986. 'order' => 99,
  987. 'description' => 'Account sample logic hook',
  988. 'file' => 'modules/Sample/sample_account_logic_hook_file.php',
  989. 'class' => 'SampleLogicClass',
  990. 'function' => 'accountAfterSave',
  991. ),
  992. ),
  993. ... blah blah ...
  994. );
  995. */
  996. function enable_manifest_logichooks() {
  997. if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
  998. return;
  999. }
  1000. foreach($this->installdefs['logic_hooks'] as $hook ) {
  1001. check_logic_hook_file($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function']));
  1002. }
  1003. }
  1004. function disable_manifest_logichooks() {
  1005. if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
  1006. return;
  1007. }
  1008. foreach($this->installdefs['logic_hooks'] as $hook ) {
  1009. remove_logic_hook($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function']));
  1010. }
  1011. }
  1012. /**
  1013. * Check labels inside label files and remove them
  1014. *
  1015. * @param $basePath - path to files with labels
  1016. * @param array $labelDefinitions - format like output from AbstractRelationship buildLabels()
  1017. */
  1018. public function uninstallLabels($basePath, $labelDefinitions)
  1019. {
  1020. foreach ($labelDefinitions as $definition) {
  1021. $filename = $basePath . "{$definition['module']}.php";
  1022. if (!file_exists($filename)) {
  1023. continue;
  1024. }
  1025. $uninstalLabes = $this->getLabelsToUninstall($labelDefinitions);
  1026. $this->uninstallLabel($uninstalLabes, $definition, $filename);
  1027. }
  1028. }
  1029. /**
  1030. * Check labels inside label file and remove them
  1031. *
  1032. * @param $uninstalLabes
  1033. * @param $definition
  1034. * @param $filename
  1035. */
  1036. protected function uninstallLabel($uninstalLabes, $definition, $filename)
  1037. {
  1038. $app_list_strings = array();
  1039. $mod_strings = array();
  1040. $stringsName = $definition['module'] == 'application' ? 'app_list_strings' : 'mod_strings';
  1041. include($filename);
  1042. if ('app_list_strings' == $stringsName) {
  1043. $strings = $app_list_strings;
  1044. } else {
  1045. $strings = $mod_strings;
  1046. }
  1047. foreach ($uninstalLabes AS $label) {
  1048. if (isset($strings[$label])) {
  1049. unset($strings[$label]);
  1050. }
  1051. }
  1052. if (count($strings)) {
  1053. $this->saveContentToFile($filename, $stringsName, $strings);
  1054. } else {
  1055. unlink($filename);
  1056. }
  1057. }
  1058. /**
  1059. * Save labels that not need be uninstalled at this case
  1060. *
  1061. * @param $filename
  1062. * @param $stringsName
  1063. * @param $strings
  1064. */
  1065. protected function saveContentToFile($filename, $stringsName, $strings)
  1066. {
  1067. $fileContent = "<?php\n//THIS FILE IS AUTO GENERATED, DO NOT MODIFY\n";
  1068. foreach ($strings as $key => $val) {
  1069. $fileContent .= override_value_to_string_recursive2($stringsName, $key, $val);
  1070. }
  1071. sugar_file_put_contents($filename, $fileContent);
  1072. }
  1073. /**
  1074. * Uninstall extend labels
  1075. *
  1076. * @param $labelDefinitions
  1077. */
  1078. public function uninstallExtLabels($labelDefinitions)
  1079. {
  1080. foreach ($labelDefinitions as $definition) {
  1081. if (!isset($GLOBALS['sugar_config']['languages']) || !is_array($GLOBALS['sugar_config']['languages'])) {
  1082. continue;
  1083. }
  1084. foreach (array_keys($GLOBALS['sugar_config']['languages']) AS $language) {
  1085. $pathDef = array(
  1086. 'language' => $language,
  1087. 'to_module' => $definition['module']
  1088. );
  1089. $path = $this->getInstallLanguagesPath($pathDef);
  1090. if (file_exists($path)) {
  1091. unlink($path);
  1092. }
  1093. }
  1094. }
  1095. }
  1096. /**
  1097. * Returns the names of the label(key 'system_label') from a multi-dimensional array $labelDefinitions
  1098. *
  1099. * @param $labelDefinitions
  1100. * @return array of labels
  1101. */
  1102. protected function getLabelsToUninstall($labelDefinitions)
  1103. {
  1104. $labels = array();
  1105. foreach($labelDefinitions AS $definition){
  1106. $labels[] = $definition['system_label'];
  1107. }
  1108. return $labels;
  1109. }
  1110. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  1111. function copy_path($from, $to, $backup_path='', $uninstall=false){
  1112. //function copy_path($from, $to){
  1113. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  1114. $to = str_replace('<basepath>', $this->base_dir, $to);
  1115. if(!$uninstall) {
  1116. $from = str_replace('<basepath>', $this->base_dir, $from);
  1117. $GLOBALS['log']->debug('Copy ' . $from);
  1118. }
  1119. else {
  1120. $from = str_replace('<basepath>', $backup_path, $from);
  1121. //$GLOBALS['log']->debug('Restore ' . $from);
  1122. }
  1123. $from = clean_path($from);
  1124. $to = clean_path($to);
  1125. $dir = dirname($to);
  1126. //there are cases where if we need to create a directory in the root directory
  1127. if($dir == '.' && is_dir($from)){
  1128. $dir = $to;
  1129. }
  1130. if(!sugar_is_dir($dir, 'instance'))
  1131. mkdir_recursive($dir, true);
  1132. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  1133. if(empty($backup_path)) {
  1134. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  1135. if(!copy_recursive($from, $to)){
  1136. die('Failed to copy ' . $from. ' ' . $to);
  1137. }
  1138. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  1139. }
  1140. elseif(!$this->copy_recursive_with_backup($from, $to, $backup_path, $uninstall)){
  1141. die('Failed to copy ' . $from. ' to ' . $to);
  1142. }
  1143. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  1144. }
  1145. function install_custom_fields($fields){
  1146. global $beanList, $beanFiles;
  1147. include('include/modules.php');
  1148. require_once('modules/DynamicFields/FieldCases.php');
  1149. foreach($fields as $field){
  1150. $installed = false;
  1151. if(isset($beanList[ $field['module']])){
  1152. $class = $beanList[ $field['module']];
  1153. if(!isset($field['ext4']))$field['ext4'] = '';
  1154. if(!isset($field['mass_update']))$field['mass_update'] = 0;
  1155. if(!isset($field['duplicate_merge']))$field['duplicate_merge'] = 0;
  1156. if(!isset($field['help']))$field['help'] = '';
  1157. //Merge contents of the sugar field extension if we copied one over
  1158. if (file_exists("custom/Extension/modules/{$field['module']}/Ext/Vardefs/sugarfield_{$field['name']}.php"))
  1159. {
  1160. $dictionary = array();
  1161. include ("custom/Extension/modules/{$field['module']}/Ext/Vardefs/sugarfield_{$field['name']}.php");
  1162. $obj = BeanFactory::getObjectName($field['module']);
  1163. if (!empty($dictionary[$obj]['fields'][$field['name']])) {
  1164. $field = array_merge($dictionary[$obj]['fields'][$field['name']], $field);
  1165. }
  1166. }
  1167. if(file_exists($beanFiles[$class])){
  1168. require_once($beanFiles[$class]);
  1169. $mod = new $class();
  1170. $installed = true;
  1171. $fieldObject = get_widget($field['type']);
  1172. $fieldObject->populateFromRow($field);
  1173. $mod->custom_fields->use_existing_labels = true;
  1174. $mod->custom_fields->addFieldObject($fieldObject);
  1175. }
  1176. }
  1177. if(!$installed){
  1178. $GLOBALS['log']->debug('Could not install custom field ' . $field['name'] . ' for module ' . $field['module'] . ': Module does not exist');
  1179. }
  1180. }
  1181. }
  1182. function uninstall_custom_fields($fields){
  1183. global $beanList, $beanFiles;
  1184. require_once('modules/DynamicFields/DynamicField.php');
  1185. $dyField = new DynamicField();
  1186. foreach($fields as $field){
  1187. $class = $beanList[ $field['module']];
  1188. if(file_exists($beanFiles[$class])){
  1189. require_once($beanFiles[$class]);
  1190. $mod = new $class();
  1191. $dyField->bean = $mod;
  1192. $dyField->module = $field['module'];
  1193. $dyField->deleteField($field['name']);
  1194. }
  1195. }
  1196. }
  1197. /*
  1198. * ModuleInstaller->install_relationships calls install_relationship for every file included in the module package that defines a relationship, and then
  1199. * writes a custom/Extension/application/Ext/TableDictionary/$module.php file containing an include_once for every relationship metadata file passed to install_relationship.
  1200. * Next it calls install_vardef and install_layoutdef. Finally, it rebuilds the vardefs and layoutdefs (by calling merge_files as usual), and then calls merge_files to merge
  1201. * everything in 'Ext/TableDictionary/' into 'tabledictionary.ext.php'
  1202. */
  1203. function install_relationships ()
  1204. {
  1205. if (isset ( $this->installdefs [ 'relationships' ] ))
  1206. {
  1207. $this->log ( translate ( 'LBL_MI_IN_RELATIONSHIPS' ) ) ;
  1208. $str = "<?php \n //WARNING: The contents of this file are auto-generated\n" ;
  1209. $save_table_dictionary = false ;
  1210. if (! file_exists ( "custom/Extension/application/Ext/TableDictionary" ))
  1211. {
  1212. mkdir_recursive ( "custom/Extension/application/Ext/TableDictionary", true ) ;
  1213. }
  1214. foreach ( $this->installdefs [ 'relationships' ] as $key => $relationship )
  1215. {
  1216. $filename = basename ( $relationship [ 'meta_data' ] ) ;
  1217. $this->copy_path ( $relationship [ 'meta_data' ], 'custom/metadata/' . $filename ) ;
  1218. $this->install_relationship ( 'custom/metadata/' . $filename ) ;
  1219. $save_table_dictionary = true ;
  1220. if (! empty ( $relationship [ 'module_vardefs' ] ))
  1221. {
  1222. $relationship [ 'module_vardefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_vardefs' ] ) ;
  1223. $this->install_vardef ( $relationship [ 'module_vardefs' ], $relationship [ 'module' ] ) ;
  1224. }
  1225. if (! empty ( $relationship [ 'module_layoutdefs' ] ))
  1226. {
  1227. $relationship [ 'module_layoutdefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_layoutdefs' ] ) ;
  1228. $this->install_layoutdef ( $relationship [ 'module_layoutdefs' ], $relationship [ 'module' ] ) ;
  1229. }
  1230. $relName = strpos($filename, "MetaData") !== false ? substr($filename, 0, strlen($filename) - 12) : $filename;
  1231. $out = sugar_fopen ( "custom/Extension/application/Ext/TableDictionary/$relName.php", 'w' ) ;
  1232. fwrite ( $out, $str . "include('custom/metadata/$filename');\n\n?>" ) ;
  1233. fclose ( $out ) ;
  1234. }
  1235. Relationship::delete_cache();
  1236. $this->rebuild_vardefs () ;
  1237. $this->rebuild_layoutdefs () ;
  1238. if ($save_table_dictionary)
  1239. {
  1240. $this->rebuild_tabledictionary () ;
  1241. }
  1242. require_once("data/Relationships/RelationshipFactory.php");
  1243. SugarRelationshipFactory::deleteCache();
  1244. }
  1245. }
  1246. /*
  1247. * Install_relationship obtains a set of relationship definitions from the filename passed in as a parameter.
  1248. * For each definition it calls db->createTableParams to build the relationships table if it does not exist,
  1249. * and SugarBean::createRelationshipMeta to add the relationship into the 'relationships' table.
  1250. */
  1251. function install_relationship($file)
  1252. {
  1253. $_REQUEST['moduleInstaller'] = true;
  1254. if(!file_exists($file))
  1255. {
  1256. $GLOBALS['log']->debug( 'File does not exists : '.$file);
  1257. return;
  1258. }
  1259. include($file);
  1260. $rel_dictionary = $dictionary;
  1261. foreach ($rel_dictionary as $rel_name => $rel_data)
  1262. {
  1263. $table = ''; // table is actually optional
  1264. // check if we have a table definition - not all relationships require a join table
  1265. if ( isset( $rel_data[ 'table' ] ) )
  1266. {
  1267. $table = $rel_data[ 'table' ];
  1268. if(!$this->db->tableExists($table))
  1269. {
  1270. $this->db->createTableParams($table, $rel_data[ 'fields' ], $rel_data[ 'indices' ]);
  1271. }
  1272. }
  1273. if(!$this->silent)
  1274. $GLOBALS['log']->debug("Processing relationship meta for ". $rel_name."...");
  1275. SugarBean::createRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
  1276. Relationship::delete_cache();
  1277. if(!$this->silent)
  1278. $GLOBALS['log']->debug( 'done<br>');
  1279. }
  1280. }
  1281. function install_layoutfields() {
  1282. if (!empty ( $this->installdefs [ 'layoutfields' ] ))
  1283. {
  1284. foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
  1285. {
  1286. if (!empty($fieldSet['additional_fields']))
  1287. {
  1288. $this->addFieldsToLayout($fieldSet['additional_fields']);
  1289. }
  1290. }
  1291. }
  1292. }
  1293. function uninstall_layoutfields() {
  1294. if (!empty ( $this->installdefs [ 'layoutfields' ] ))
  1295. {
  1296. foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
  1297. {
  1298. if (!empty($fieldSet['additional_fields']))
  1299. {
  1300. $this->removeFieldsFromLayout($fieldSet['additional_fields']);
  1301. }
  1302. }
  1303. }
  1304. }
  1305. function uninstall_relationship($file, $rel_dictionary = null){
  1306. if ($rel_dictionary == null)
  1307. {
  1308. if(!file_exists($file)){
  1309. $GLOBALS['log']->debug( 'File does not exists : '.$file);
  1310. return;
  1311. }
  1312. include($file);
  1313. $rel_dictionary = $dictionary;
  1314. }
  1315. foreach ($rel_dictionary as $rel_name => $rel_data)
  1316. {
  1317. if (!empty($rel_data['table'])){
  1318. $table = $rel_data['table'];
  1319. }
  1320. else{
  1321. $table = ' One-to-Many ';
  1322. }
  1323. if ($this->db->tableExists($table) && isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
  1324. {
  1325. SugarBean::removeRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
  1326. $this->db->dropTableName($table);
  1327. if(!$this->silent) $this->log( translate('LBL_MI_UN_RELATIONSHIPS_DROP') . $table);
  1328. }
  1329. //Delete Layout defs
  1330. // check to see if we have any vardef or layoutdef entries to remove - must have a relationship['module'] parameter if we do
  1331. if (!isset($rel_data[ 'module' ]))
  1332. $mods = array(
  1333. $rel_data['relationships'][$rel_name]['lhs_module'],
  1334. $rel_data['relationships'][$rel_name]['rhs_module'],
  1335. );
  1336. else
  1337. $mods = array($rel_data[ 'module' ]);
  1338. $filename = "$rel_name.php";
  1339. foreach($mods as $mod) {
  1340. if ($mod != 'application' ) {
  1341. $basepath = "custom/Extension/modules/$mod/Ext/";
  1342. } else {
  1343. $basepath = "custom/Extension/application/Ext/";
  1344. }
  1345. foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
  1346. //remove any vardefs
  1347. $path = $basepath . "Vardefs/$fn" ;
  1348. if (file_exists( $path ))
  1349. rmdir_recursive( $path );
  1350. //remove any layoutdefs
  1351. $path = $basepath . "Layoutdefs/$fn" ;
  1352. if( file_exists( $path ))
  1353. {
  1354. rmdir_recursive( $path );
  1355. }
  1356. $path = $basepath . "WirelessLayoutdefs/$fn";
  1357. if (file_exists($path)) {
  1358. rmdir_recursive($path);
  1359. }
  1360. }
  1361. $relationships_path = 'custom/Extension/modules/relationships/';
  1362. $relationships_dirs = array(
  1363. 'layoutdefs',
  1364. 'vardefs',
  1365. 'wirelesslayoutdefs'
  1366. );
  1367. foreach ($relationships_dirs as $relationship_dir) {
  1368. $realtionship_file_path = $relationships_path . $relationship_dir . "/{$rel_name}_{$mod}.php";
  1369. if (file_exists($realtionship_file_path)) {
  1370. rmdir_recursive($realtionship_file_path);
  1371. }
  1372. }
  1373. if (file_exists($relationships_path . "relationships/{$rel_name}MetaData.php")) {
  1374. rmdir_recursive($relationships_path . "relationships/{$rel_name}MetaData.php");
  1375. }
  1376. }
  1377. foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
  1378. // remove the table dictionary extension
  1379. if ( file_exists("custom/Extension/application/Ext/TableDictionary/$fn"))
  1380. unlink("custom/Extension/application/Ext/TableDictionary/$fn");
  1381. if (file_exists("custom/metadata/{$rel_name}MetaData.php"))
  1382. unlink( "custom/metadata/{$rel_name}MetaData.php" );
  1383. }
  1384. }
  1385. }
  1386. function uninstall_relationships($include_studio_relationships = false){
  1387. $relationships = array();
  1388. //Find and remove studio created relationships.
  1389. global $beanList, $beanFiles, $dictionary;
  1390. //Load up the custom relationship definitions.
  1391. if(file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')){
  1392. include('custom/application/Ext/TableDictionary/tabledictionary.ext.php');
  1393. }
  1394. //Find all the relatioships/relate fields involving this module.
  1395. $rels_to_remove = array();
  1396. foreach($beanList as $mod => $bean) {
  1397. //Some modules like cases have a bean name that doesn't match the object name
  1398. $bean = BeanFactory::getObjectName($mod);
  1399. VardefManager::loadVardef($mod, $bean);
  1400. //We can skip modules that are in this package as they will be removed anyhow
  1401. if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields']))
  1402. {
  1403. $field_defs = $dictionary[$bean]['fields'];
  1404. foreach($field_defs as $field => $def)
  1405. {
  1406. //Weed out most fields first
  1407. if (isset ($def['type']))
  1408. {
  1409. //Custom relationships created in the relationship editor
  1410. if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']]))
  1411. {
  1412. $rel_name = $def['relationship'];
  1413. $rel_def = $dictionary[$rel_name]['relationships'][$rel_name];
  1414. //Check against mods to be removed.
  1415. foreach($this->modulesInPackage as $removed_mod) {
  1416. if ($rel_def['lhs_module'] == $removed_mod || $rel_def['rhs_module'] == $removed_mod )
  1417. {
  1418. $dictionary[$rel_name]['from_studio'] = true;
  1419. $relationships[$rel_name] = $dictionary[$rel_name];
  1420. }
  1421. }
  1422. }
  1423. //Custom "relate" fields created in studio also need to be removed
  1424. if ($def['type'] == 'relate' && isset($def['module'])) {
  1425. foreach($this->modulesInPackage as $removed_mod) {
  1426. if ($def['module'] == $removed_mod)
  1427. {
  1428. require_once 'modules/ModuleBuilder/Module/StudioModule.php' ;
  1429. $studioMod = new StudioModule ( $mod );
  1430. $studioMod->removeFieldFromLayouts( $field );
  1431. if (isset($def['custom_module'])) {
  1432. require_once ('modules/DynamicFields/DynamicField.php') ;
  1433. require_once ($beanFiles [ $bean ]) ;
  1434. $seed = new $bean ( ) ;
  1435. $df = new DynamicField ( $mod ) ;
  1436. $df->setup ( $seed ) ;
  1437. //Need to load the entire field_meta_data for some field types
  1438. $field_obj = $df->getFieldWidget($mod, $field);
  1439. $field_obj->delete ( $df ) ;
  1440. }
  1441. }
  1442. }
  1443. }
  1444. }
  1445. }
  1446. }
  1447. }
  1448. $this->uninstall_relationship(null, $relationships);
  1449. if(isset($this->installdefs['relationships'])) {
  1450. $relationships = $this->installdefs['relationships'];
  1451. $this->log(translate('LBL_MI_UN_RELATIONSHIPS') );
  1452. foreach($relationships as $relationship)
  1453. {
  1454. // remove the metadata entry
  1455. $filename = basename ( $relationship['meta_data'] );
  1456. $pathname = (file_exists("custom/metadata/$filename")) ? "custom/metadata/$filename" : "metadata/$filename" ;
  1457. if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
  1458. $this->uninstall_relationship( $pathname );
  1459. if (file_exists($pathname))
  1460. unlink( $pathname );
  1461. }
  1462. }
  1463. if (file_exists("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php"))
  1464. unlink("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php");
  1465. Relationship::delete_cache();
  1466. $this->rebuild_tabledictionary();
  1467. }
  1468. function uninstall($base_dir){
  1469. if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
  1470. global $app_strings;
  1471. $total_steps = 5; //min steps with no tasks
  1472. $current_step = 0;
  1473. $this->base_dir = $base_dir;
  1474. $tasks = array(
  1475. 'pre_uninstall',
  1476. 'uninstall_relationships',
  1477. 'uninstall_copy',
  1478. 'uninstall_dcactions',
  1479. 'uninstall_dashlets',
  1480. 'uninstall_connectors',
  1481. 'uninstall_layoutfields',
  1482. 'uninstall_extensions',
  1483. 'uninstall_global_search',
  1484. 'disable_manifest_logichooks',
  1485. 'post_uninstall',
  1486. );
  1487. $total_steps += count($tasks); //now the real number of steps
  1488. if(file_exists($this->base_dir . '/manifest.php')){
  1489. if(!$this->silent){
  1490. $current_step++;
  1491. display_progress_bar('install', $current_step, $total_steps);
  1492. echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
  1493. }
  1494. global $moduleList;
  1495. include($this->base_dir . '/manifest.php');
  1496. $this->installdefs = $installdefs;
  1497. $this->id_name = $this->installdefs['id'];
  1498. $installed_modules = array();
  1499. if(isset($this->installdefs['beans'])){
  1500. foreach($this->installdefs['beans'] as $bean){
  1501. $installed_modules[] = $bean['module'];
  1502. $this->uninstall_user_prefs($bean['module']);
  1503. }
  1504. $this->modulesInPackage = $installed_modules;
  1505. $this->uninstall_beans($installed_modules);
  1506. $this->uninstall_customizations($installed_modules);
  1507. if(!$this->silent){
  1508. $current_step++;
  1509. update_progress_bar('install', $total_steps, $total_steps);
  1510. }
  1511. }
  1512. if(!$this->silent){
  1513. $current_step++;
  1514. update_progress_bar('install', $current_step, $total_steps);
  1515. }
  1516. foreach($tasks as $task){
  1517. $this->$task();
  1518. if(!$this->silent){
  1519. $current_step++;
  1520. update_progress_bar('install', $current_step, $total_steps);
  1521. }
  1522. }
  1523. if(isset($installdefs['custom_fields']) && (isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])){
  1524. $this->log(translate('LBL_MI_UN_CUSTOMFIELD'));
  1525. $this->uninstall_custom_fields($installdefs['custom_fields']);
  1526. }
  1527. if(!$this->silent){
  1528. $current_step++;
  1529. update_progress_bar('install', $current_step, $total_steps);
  1530. echo '</div>';
  1531. }
  1532. //since we are passing $silent = true to rebuildAll() in that method it will set $this->silent = true, so
  1533. //we need to save the setting to set it back after rebuildAll() completes.
  1534. $silentBak = $this->silent;
  1535. $this->rebuild_all(true);
  1536. $this->silent = $silentBak;
  1537. //#27877, If the request from MB redeploy a custom module , we will not remove the ACL actions for this package.
  1538. if( !isset($_REQUEST['action']) || $_REQUEST['action']!='DeployPackage' ){
  1539. $this->remove_acl_actions();
  1540. }
  1541. //end
  1542. if(!$this->silent){
  1543. $current_step++;
  1544. update_progress_bar('install', $current_step, $total_steps);
  1545. echo '</div>';
  1546. }
  1547. UpdateSystemTabs('Restore',$installed_modules);
  1548. //clear the unified_search_module.php file
  1549. require_once('modules/Home/UnifiedSearchAdvanced.php');
  1550. UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
  1551. $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
  1552. if(!$this->silent){
  1553. update_progress_bar('install', $total_steps, $total_steps);
  1554. }
  1555. }else{
  1556. die("No manifest.php Defined In $this->base_dir/manifest.php");
  1557. }
  1558. }
  1559. function rebuild_languages($languages = array(), $modules="")
  1560. {
  1561. foreach($languages as $language=>$value){
  1562. $this->log(translate('LBL_MI_REBUILDING') . " Language...$language");
  1563. $this->merge_files('Ext/Language/', $language.'.lang.ext.php', $language);
  1564. if($modules!=""){
  1565. foreach($modules as $module){
  1566. LanguageManager::clearLanguageCache($module, $language);
  1567. }
  1568. }
  1569. }
  1570. sugar_cache_reset();
  1571. }
  1572. function rebuild_vardefs()
  1573. {
  1574. $this->rebuildExt("Vardefs", 'vardefs.ext.php');
  1575. sugar_cache_reset();
  1576. }
  1577. function rebuild_dashletcontainers(){
  1578. $this->log(translate('LBL_MI_REBUILDING') . " DC Actions...");
  1579. $this->merge_files('Ext/DashletContainer/Containers/', 'dcactions.ext.php');
  1580. }
  1581. function rebuild_tabledictionary()
  1582. {
  1583. $this->rebuildExt("TableDictionary", 'tabledictionary.ext.php');
  1584. }
  1585. function rebuild_relationships() {
  1586. if(!$this->silent) echo translate('LBL_MI_REBUILDING') . ' Relationships';
  1587. $_REQUEST['silent'] = true;
  1588. global $beanFiles;
  1589. include('include/modules.php');
  1590. include("modules/Administration/RebuildRelationship.php");
  1591. }
  1592. function remove_acl_actions() {
  1593. global $beanFiles, $beanList, $current_user;
  1594. include('include/modules.php');
  1595. include("modules/ACL/remove_actions.php");
  1596. }
  1597. /**
  1598. * Wrapper call to modules/Administration/RepairIndex.php
  1599. */
  1600. function repair_indices() {
  1601. global $current_user,$beanFiles,$dictionary;
  1602. $this->log(translate('LBL_MI_REPAIR_INDICES'));
  1603. $_REQUEST['silent'] = true; // local var flagging echo'd output in repair script
  1604. $_REQUEST['mode'] = 'execute'; // flag to just go ahead and run the script
  1605. include("modules/Administration/RepairIndex.php");
  1606. }
  1607. /**
  1608. * Rebuilds the extension files found in custom/Extension
  1609. * @param boolean $silent
  1610. */
  1611. function rebuild_all($silent=false){
  1612. if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
  1613. $this->silent=$silent;
  1614. global $sugar_config;
  1615. //Check for new module extensions
  1616. $this->rebuild_modules();
  1617. $this->rebuild_languages($sugar_config['languages']);
  1618. $this->rebuild_extensions();
  1619. $this->rebuild_dashletcontainers();
  1620. $this->rebuild_relationships();
  1621. $this->rebuild_tabledictionary();
  1622. $this->reset_opcodes();
  1623. sugar_cache_reset();
  1624. }
  1625. /*
  1626. * ModuleInstaller->merge_files runs over the list of all modules already installed in /modules. For each $module it reads the contents of every file in
  1627. * custom/Extension/modules/$module/<path> (_override files last) and concatenates them to custom/modules/$module/<path>/<file>.
  1628. * Then it does the same thing in custom/Extension/application/<path>, concatenating those files and copying the result to custom/application/<path>/<file>
  1629. */
  1630. function merge_files($path, $name, $filter = '', $application = false){
  1631. if(!$application){
  1632. $GLOBALS['log']->debug( get_class($this)."->merge_files() : merging module files in custom/Extension/modules/<module>/$path to custom/modules/<module>/$path$name");
  1633. foreach($this->modules as $module){
  1634. //$GLOBALS['log']->debug("Merging Files for: ".$module);
  1635. //$GLOBALS['log']->debug("Merging Files for path: ".$path);
  1636. $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
  1637. $extpath = "modules/$module/$path";
  1638. $module_install = 'custom/Extension/'.$extpath;
  1639. $shouldSave = false;
  1640. if(is_dir($module_install)){
  1641. $dir = dir($module_install);
  1642. $shouldSave = true;
  1643. $override = array();
  1644. while($entry = $dir->read()){
  1645. if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
  1646. && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
  1647. {
  1648. if (substr($entry, 0, 9) == '_override') {
  1649. $override[] = $entry;
  1650. } else {
  1651. $file = file_get_contents($module_install . '/' . $entry);
  1652. $GLOBALS['log']->debug(get_class($this)."->merge_files(): found {$module_install}{$entry}") ;
  1653. $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
  1654. }
  1655. }
  1656. }
  1657. foreach ($override as $entry) {
  1658. $file = file_get_contents($module_install . '/' . $entry);
  1659. $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
  1660. }
  1661. }
  1662. $extension .= "\n?>";
  1663. if($shouldSave){
  1664. if(!file_exists("custom/$extpath")) {
  1665. mkdir_recursive("custom/$extpath", true);
  1666. }
  1667. $out = sugar_fopen("custom/$extpath/$name", 'w');
  1668. fwrite($out,$extension);
  1669. fclose($out);
  1670. }else{
  1671. if(file_exists("custom/$extpath/$name")){
  1672. unlink("custom/$extpath/$name");
  1673. }
  1674. }
  1675. }
  1676. }
  1677. $GLOBALS['log']->debug("Merging application files for $name in $path");
  1678. //Now the application stuff
  1679. $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
  1680. $extpath = "application/$path";
  1681. $module_install = 'custom/Extension/'.$extpath;
  1682. $shouldSave = false;
  1683. if(is_dir($module_install)){
  1684. $dir = dir($module_install);
  1685. while($entry = $dir->read()){
  1686. $shouldSave = true;
  1687. if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
  1688. && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
  1689. {
  1690. $file = file_get_contents($module_install . '/' . $entry);
  1691. $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
  1692. }
  1693. }
  1694. }
  1695. $extension .= "\n?>";
  1696. if($shouldSave){
  1697. if(!file_exists("custom/$extpath")){
  1698. mkdir_recursive("custom/$extpath", true);
  1699. }
  1700. $out = sugar_fopen("custom/$extpath/$name", 'w');
  1701. fwrite($out,$extension);
  1702. fclose($out);
  1703. }else{
  1704. if(file_exists("custom/$extpath/$name")){
  1705. unlink("custom/$extpath/$name");
  1706. }
  1707. }
  1708. }
  1709. function install_modules()
  1710. {
  1711. $this->installed_modules = array();
  1712. $this->tab_modules = array();
  1713. if(isset($this->installdefs['beans'])){
  1714. $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
  1715. foreach($this->installdefs['beans'] as $bean){
  1716. if(!empty($bean['module']) && !empty($bean['class']) && !empty($bean['path'])){
  1717. $module = $bean['module'];
  1718. $class = $bean['class'];
  1719. $path = $bean['path'];
  1720. $str .= "\$beanList['$module'] = '$class';\n";
  1721. $str .= "\$beanFiles['$class'] = '$path';\n";
  1722. if($bean['tab']){
  1723. $str .= "\$moduleList[] = '$module';\n";
  1724. $this->install_user_prefs($module, empty($bean['hide_by_default']));
  1725. $this->tab_modules[] = $module;
  1726. }else{
  1727. $str .= "\$modules_exempt_from_availability_check['$module'] = '$module';\n";
  1728. $str .= "\$report_include_modules['$module'] = '$module';\n";
  1729. $str .= "\$modInvisList[] = '$module';\n";
  1730. }
  1731. $this->installed_modules[] = $module;
  1732. }else{
  1733. $errors[] = 'Bean array not well defined.';
  1734. $this->abort($errors);
  1735. }
  1736. }
  1737. $str.= "\n?>";
  1738. if(!file_exists("custom/Extension/application/Ext/Include")){
  1739. mkdir_recursive("custom/Extension/application/Ext/Include", true);
  1740. }
  1741. file_put_contents("custom/Extension/application/Ext/Include/{$this->id_name}.php", $str);
  1742. }
  1743. }
  1744. /*
  1745. * ModuleInstaller->install_beans runs through the list of beans given, instantiates each bean, calls bean->create_tables, and then calls SugarBean::createRelationshipMeta for the
  1746. * bean/module.
  1747. */
  1748. function install_beans($beans){
  1749. include('include/modules.php');
  1750. foreach($beans as $bean){
  1751. $this->log( translate('LBL_MI_IN_BEAN') . " $bean");
  1752. if(isset($beanList[$bean])){
  1753. $class = $beanList[$bean];
  1754. if(file_exists($beanFiles[$class])){
  1755. require_once($beanFiles[$class]);
  1756. $mod = new $class();
  1757. //#30273
  1758. if(is_subclass_of($mod, 'SugarBean') && $mod->disable_vardefs == false ){
  1759. $GLOBALS['log']->debug( "Creating Tables Bean : $bean");
  1760. $mod->create_tables();
  1761. SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir);
  1762. }
  1763. }else{
  1764. $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
  1765. }
  1766. }
  1767. }
  1768. }
  1769. function uninstall_beans($beans){
  1770. include('include/modules.php');
  1771. foreach($beans as $bean){
  1772. $this->log( translate('LBL_MI_UN_BEAN') . " $bean");
  1773. if(isset($beanList[$bean])){
  1774. $class = $beanList[$bean];
  1775. if(file_exists($beanFiles[$class])){
  1776. require_once($beanFiles[$class]);
  1777. $mod = new $class();
  1778. if(is_subclass_of($mod, 'SugarBean')){
  1779. $GLOBALS['log']->debug( "Drop Tables : $bean");
  1780. if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
  1781. $mod->drop_tables();
  1782. }
  1783. }else{
  1784. $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
  1785. }
  1786. }
  1787. }
  1788. }
  1789. /**
  1790. * Remove any customizations made within Studio while the module was installed.
  1791. */
  1792. function uninstall_customizations($beans){
  1793. foreach($beans as $bean){
  1794. $dirs = array(
  1795. 'custom/modules/' . $bean,
  1796. 'custom/Extension/modules/' . $bean,
  1797. 'custom/working/modules/' . $bean
  1798. );
  1799. foreach($dirs as $dir)
  1800. {
  1801. if(is_dir($dir)){
  1802. rmdir_recursive($dir);
  1803. }
  1804. }
  1805. }
  1806. }
  1807. function log($str){
  1808. $GLOBALS['log']->debug('ModuleInstaller:'. $str);
  1809. if(!$this->silent){
  1810. echo $str . '<br>';
  1811. }
  1812. }
  1813. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:15:18 PM */
  1814. function copy_recursive_with_backup( $source, $dest, $backup_path, $uninstall=false ) {
  1815. if(is_file($source)) {
  1816. if($uninstall) {
  1817. $GLOBALS['log']->debug("Restoring ... " . $source. " to " .$dest );
  1818. if(copy( $source, $dest)) {
  1819. if(is_writable($dest))
  1820. sugar_touch( $dest, filemtime($source) );
  1821. return(unlink($source));
  1822. }
  1823. else {
  1824. $GLOBALS['log']->debug( "Can't restore file: " . $source );
  1825. return true;
  1826. }
  1827. }
  1828. else {
  1829. if(file_exists($dest)) {
  1830. $rest = clean_path($backup_path."/$dest");
  1831. if( !is_dir(dirname($rest)) )
  1832. mkdir_recursive(dirname($rest), true);
  1833. $GLOBALS['log']->debug("Backup ... " . $dest. " to " .$rest );
  1834. if(copy( $dest, $rest)) {
  1835. if(is_writable($rest))
  1836. sugar_touch( $rest, filemtime($dest) );
  1837. }
  1838. else {
  1839. $GLOBALS['log']->debug( "Can't backup file: " . $dest );
  1840. }
  1841. }
  1842. return( copy( $source, $dest ) );
  1843. }
  1844. }
  1845. elseif(!is_dir($source)) {
  1846. if($uninstall) {
  1847. if(is_file($dest))
  1848. return(unlink($dest));
  1849. else {
  1850. //don't do anything we already cleaned up the files using uninstall_new_files
  1851. return true;
  1852. }
  1853. }
  1854. else
  1855. return false;
  1856. }
  1857. if( !is_dir($dest) && !$uninstall){
  1858. sugar_mkdir( $dest );
  1859. }
  1860. $status = true;
  1861. $d = dir( $source );
  1862. while( $f = $d->read() ){
  1863. if( $f == "." || $f == ".." ){
  1864. continue;
  1865. }
  1866. $status &= $this->copy_recursive_with_backup( "$source/$f", "$dest/$f", $backup_path, $uninstall );
  1867. }
  1868. $d->close();
  1869. return( $status );
  1870. }
  1871. private function dir_get_files($path, $base_path){
  1872. $files = array();
  1873. if(!is_dir($path))return $files;
  1874. $d = dir($path);
  1875. while ($e = $d->read()){
  1876. //ignore invisible files . .. ._MACOSX
  1877. if(substr($e, 0, 1) == '.')continue;
  1878. if(is_file($path . '/' . $e))$files[str_replace($base_path , '', $path . '/' . $e)] = str_replace($base_path , '', $path . '/' . $e);
  1879. if(is_dir($path . '/' . $e))$files = array_merge($files, $this->dir_get_files($path . '/' . $e, $base_path));
  1880. }
  1881. $d->close();
  1882. return $files;
  1883. }
  1884. private function dir_file_count($path){
  1885. //if its a file then it has at least 1 file in the directory
  1886. if(is_file($path)) return 1;
  1887. if(!is_dir($path)) return 0;
  1888. $d = dir($path);
  1889. $count = 0;
  1890. while ($e = $d->read()){
  1891. //ignore invisible files . .. ._MACOSX
  1892. if(substr($e, 0, 1) == '.')continue;
  1893. if(is_file($path . '/' . $e))$count++;
  1894. if(is_dir($path . '/' . $e))$count += $this->dir_file_count($path . '/' . $e);
  1895. }
  1896. $d->close();
  1897. return $count;
  1898. }
  1899. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:15:34 PM */
  1900. /**
  1901. * Static function which allows a module developer to abort their progress, pass in an array of errors and
  1902. * redirect back to the main module loader page
  1903. *
  1904. * @param errors an array of error messages which will be displayed on the
  1905. * main module loader page once it is loaded.
  1906. */
  1907. function abort($errors = array()){
  1908. //set the errors onto the session so we can display them one the moduler loader page loads
  1909. $_SESSION['MODULEINSTALLER_ERRORS'] = $errors;
  1910. echo '<META HTTP-EQUIV="Refresh" content="0;url=index.php?module=Administration&action=UpgradeWizard&view=module">';
  1911. die();
  1912. //header('Location: index.php?module=Administration&action=UpgradeWizard&view=module');
  1913. }
  1914. /**
  1915. * Return the set of errors stored in the SESSION
  1916. *
  1917. * @return an array of errors
  1918. */
  1919. function getErrors(){
  1920. if(!empty($_SESSION['MODULEINSTALLER_ERRORS'])){
  1921. $errors = $_SESSION['MODULEINSTALLER_ERRORS'];
  1922. unset($_SESSION['MODULEINSTALLER_ERRORS']);
  1923. return $errors;
  1924. }
  1925. else
  1926. return null;
  1927. }
  1928. /*
  1929. * Add any fields to the DetailView and EditView of the appropriate modules
  1930. * Only add into deployed modules, as addFieldsToUndeployedLayouts has done this already for undeployed modules (and the admin might have edited the layouts already)
  1931. * @param array $layoutAdditions An array of module => fieldname
  1932. * return null
  1933. */
  1934. function addFieldsToLayout($layoutAdditions) {
  1935. require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
  1936. // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
  1937. // In either case, we don't want to attempt to add a relate field to them
  1938. // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
  1939. $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
  1940. foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
  1941. {
  1942. if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
  1943. {
  1944. foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
  1945. {
  1946. $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
  1947. $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
  1948. $parser->addField ( array ( 'name' => $fieldName ) ) ;
  1949. $parser->handleSave ( false ) ;
  1950. }
  1951. }
  1952. }
  1953. }
  1954. function removeFieldsFromLayout($layoutAdditions) {
  1955. require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
  1956. // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
  1957. // In either case, we don't want to attempt to add a relate field to them
  1958. // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
  1959. $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
  1960. foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
  1961. {
  1962. if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
  1963. {
  1964. foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
  1965. {
  1966. $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
  1967. $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
  1968. $parser->removeField ( $fieldName ) ;
  1969. $parser->handleSave ( false ) ;
  1970. }
  1971. }
  1972. }
  1973. }
  1974. ///////////////////
  1975. //********** DISABLE/ENABLE FUNCTIONS
  1976. ///////////////////
  1977. function enable($base_dir, $is_upgrade = false, $previous_version = ''){
  1978. global $app_strings;
  1979. $this->base_dir = $base_dir;
  1980. $total_steps = 3; //minimum number of steps with no tasks
  1981. $current_step = 0;
  1982. $tasks = array(
  1983. 'enable_copy',
  1984. 'enable_dashlets',
  1985. 'enable_relationships',
  1986. 'enable_extensions',
  1987. 'enable_global_search',
  1988. 'enable_manifest_logichooks',
  1989. 'reset_opcodes',
  1990. );
  1991. $total_steps += count($tasks);
  1992. if(file_exists($this->base_dir . '/manifest.php')){
  1993. if(!$this->silent){
  1994. $current_step++;
  1995. display_progress_bar('install', $current_step, $total_steps);
  1996. echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
  1997. }
  1998. require_once($this->base_dir . '/manifest.php');
  1999. if($is_upgrade && !empty($previous_version)){
  2000. //check if the upgrade path exists
  2001. if(!empty($upgrade_manifest)){
  2002. if(!empty($upgrade_manifest['upgrade_paths'])){
  2003. if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
  2004. $installdefs = $upgrade_manifest['upgrade_paths'][$previous_version];
  2005. }else{
  2006. $errors[] = 'No Upgrade Path Found in manifest.';
  2007. $this->abort($errors);
  2008. }//fi
  2009. }//fi
  2010. }//fi
  2011. }//fi
  2012. $this->id_name = $installdefs['id'];
  2013. $this->installdefs = $installdefs;
  2014. $installed_modules = array();
  2015. if(isset($installdefs['beans'])){
  2016. foreach($this->installdefs['beans'] as $bean){
  2017. $installed_modules[] = $bean['module'];
  2018. }
  2019. }
  2020. if(!$this->silent){
  2021. $current_step++;
  2022. update_progress_bar('install', $current_step, $total_steps);
  2023. }
  2024. foreach($tasks as $task){
  2025. $this->$task();
  2026. if(!$this->silent){
  2027. $current_step++;
  2028. update_progress_bar('install', $current_step, $total_steps);
  2029. }
  2030. }
  2031. if(!$this->silent){
  2032. $current_step++;
  2033. update_progress_bar('install', $current_step, $total_steps);
  2034. echo '</div>';
  2035. }
  2036. UpdateSystemTabs('Add',$installed_modules);
  2037. $GLOBALS['log']->debug('Complete');
  2038. }else{
  2039. die("No \$installdefs Defined In $this->base_dir/manifest.php");
  2040. }
  2041. }
  2042. function disable($base_dir){
  2043. global $app_strings;
  2044. $total_steps = 3; //min steps with no tasks
  2045. $current_step = 0;
  2046. $this->base_dir = $base_dir;
  2047. $tasks = array(
  2048. 'disable_copy',
  2049. 'disable_dashlets',
  2050. 'disable_relationships',
  2051. 'disable_extensions',
  2052. 'disable_global_search',
  2053. 'disable_manifest_logichooks',
  2054. 'reset_opcodes',
  2055. );
  2056. $total_steps += count($tasks); //now the real number of steps
  2057. if(file_exists($this->base_dir . '/manifest.php')){
  2058. if(!$this->silent){
  2059. $current_step++;
  2060. display_progress_bar('install', $current_step, $total_steps);
  2061. echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
  2062. }
  2063. require_once($this->base_dir . '/manifest.php');
  2064. $this->installdefs = $installdefs;
  2065. $this->id_name = $this->installdefs['id'];
  2066. $installed_modules = array();
  2067. if(isset($this->installdefs['beans'])){
  2068. foreach($this->installdefs['beans'] as $bean){
  2069. $installed_modules[] = $bean['module'];
  2070. }
  2071. }
  2072. if(!$this->silent){
  2073. $current_step++;
  2074. update_progress_bar('install', $current_step, $total_steps);
  2075. }
  2076. foreach($tasks as $task){
  2077. $this->$task();
  2078. if(!$this->silent){
  2079. $current_step++;
  2080. update_progress_bar('install', $current_step, $total_steps);
  2081. }
  2082. }
  2083. if(!$this->silent){
  2084. $current_step++;
  2085. update_progress_bar('install', $current_step, $total_steps);
  2086. echo '</div>';
  2087. }
  2088. UpdateSystemTabs('Restore',$installed_modules);
  2089. }else{
  2090. die("No manifest.php Defined In $this->base_dir/manifest.php");
  2091. }
  2092. }
  2093. function enable_vardef($to_module)
  2094. {
  2095. $this->enableExt("vardefs", "Vardefs", $to_module);
  2096. }
  2097. function enable_layoutdef($to_module)
  2098. {
  2099. $this->enableExt("layoutdefs", "Layoutdefs", $to_module);
  2100. }
  2101. function enable_relationships(){
  2102. if(isset($this->installdefs['relationships'])){
  2103. $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
  2104. $save_table_dictionary = false;
  2105. foreach($this->installdefs['relationships'] as $relationship){
  2106. $filename =basename($relationship['meta_data']);
  2107. $save_table_dictionary = true;
  2108. $str .= "include_once('metadata/$filename');\n";
  2109. if (empty($relationship['module']))
  2110. continue;
  2111. if(!empty($relationship['module_vardefs'])){
  2112. $this->enable_vardef($relationship['module']);
  2113. }
  2114. if(!empty($relationship['module_layoutdefs'])){
  2115. $this->enable_layoutdef($relationship['module']);
  2116. }
  2117. }
  2118. $this->rebuild_vardefs();
  2119. $this->rebuild_layoutdefs();
  2120. if($save_table_dictionary){
  2121. if(!file_exists("custom/Extension/application/Ext/TableDictionary")){
  2122. mkdir_recursive("custom/Extension/application/Ext/TableDictionary", true);
  2123. }
  2124. if (file_exists("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php"))
  2125. rename("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/$this->id_name.php");
  2126. $this->rebuild_tabledictionary();
  2127. }
  2128. }
  2129. }
  2130. function disable_relationships($action = 'disable'){
  2131. if(isset($this->installdefs['relationships'])){
  2132. foreach($this->installdefs['relationships'] as $relationship){
  2133. $filename = basename($relationship['meta_data']);
  2134. $relName = substr($filename, -12) == "MetaData.php" ? substr($filename,0,strlen($filename) - 12) : "";
  2135. if (empty($relationship['module']) && empty($relName))
  2136. continue;
  2137. //remove the vardefs
  2138. if (empty($relName))
  2139. $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Vardefs';
  2140. if(!empty($relationship['module']) && $relationship['module'] == 'application'){
  2141. $path ='custom/Extension/' . $relationship['module']. '/Ext/Vardefs';
  2142. }
  2143. if(!empty($relationship['module_vardefs']) && file_exists($path . '/'. $this->id_name . '.php')){
  2144. mkdir_recursive($path . '/'.DISABLED_PATH, true);
  2145. rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
  2146. }
  2147. //remove the layoutdefs
  2148. if ( !empty($relationship['module']) ) {
  2149. $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Layoutdefs';
  2150. if($relationship['module'] == 'application'){
  2151. $path ='custom/Extension/' . $relationship['module']. '/Ext/Layoutdefs';
  2152. }
  2153. }
  2154. if(!empty($relationship['module_layoutdefs']) && file_exists($path . '/'. $this->id_name . '.php')){
  2155. mkdir_recursive($path . '/'.DISABLED_PATH, true);
  2156. rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
  2157. }
  2158. }
  2159. if(file_exists("custom/Extension/application/Ext/TableDictionary/$this->id_name.php")){
  2160. mkdir_recursive("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH, true);
  2161. rename("custom/Extension/application/Ext/TableDictionary/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php");
  2162. }
  2163. $this->rebuild_tabledictionary();
  2164. $this->rebuild_vardefs();
  2165. $this->rebuild_layoutdefs();
  2166. }
  2167. }
  2168. function enable_dashlets(){
  2169. if(isset($this->installdefs['dashlets'])){
  2170. foreach($this->installdefs['dashlets'] as $cp){
  2171. $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
  2172. $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
  2173. $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
  2174. $GLOBALS['log']->debug("Enabling Dashlet " . $cp['name'] . "..." . $cp['from'] );
  2175. if (file_exists($disabled_path))
  2176. {
  2177. rename($disabled_path, $path);
  2178. }
  2179. }
  2180. include('modules/Administration/RebuildDashlets.php');
  2181. }
  2182. }
  2183. function disable_dashlets(){
  2184. if(isset($this->installdefs['dashlets'])){
  2185. foreach($this->installdefs['dashlets'] as $cp){
  2186. $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
  2187. $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
  2188. $GLOBALS['log']->debug('Disabling ' .$path);
  2189. if (file_exists($path))
  2190. {
  2191. mkdir_recursive('custom/modules/Home/'.DISABLED_PATH.'Dashlets/', true);
  2192. rename( $path, $disabled_path);
  2193. }
  2194. }
  2195. include('modules/Administration/RebuildDashlets.php');
  2196. }
  2197. }
  2198. function enable_copy(){
  2199. //copy files back onto file system. first perform md5 check to determine if anything has been modified
  2200. //here we should just go through the files in the -restore directory and copy those back
  2201. if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
  2202. if(!empty($this->installdefs['copy'])){
  2203. foreach($this->installdefs['copy'] as $cp){
  2204. $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
  2205. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
  2206. //check if this file exists in the -restore directory
  2207. if(file_exists($backup_path)){
  2208. //since the file exists, then we want do an md5 of the install version and the file system version
  2209. //if(is_file($backup_path) && md5_file($backup_path) == md5_file($cp['to'])){
  2210. //since the files are the same then we can safely move back from the -restore
  2211. //directory into the file system
  2212. $GLOBALS['log']->debug("ENABLE COPY:: FROM: ".$cp['from']. " TO: ".$cp['to']);
  2213. $this->copy_path($cp['from'], $cp['to']);
  2214. /*}else{
  2215. //since they are not equal then we need to prompt the user
  2216. }*/
  2217. }//fi
  2218. }//rof
  2219. }//fi
  2220. }//fi
  2221. }
  2222. function disable_copy(){
  2223. //when we disable we want to copy the -restore files back into the file system
  2224. //but we should check the version in the module install against the version on the file system
  2225. //if they match then we can copy the file back, but otherwise we should ask the user.
  2226. // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy()');
  2227. if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
  2228. // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy():mi_overwrite_files=true');
  2229. if(!empty($this->installdefs['copy'])){
  2230. // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy(): installdefs not empty');
  2231. foreach($this->installdefs['copy'] as $cp){
  2232. $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
  2233. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); // bug 16966 tyoung - replaced missing assignment to $backup_path
  2234. //check if this file exists in the -restore directory
  2235. // $GLOBALS['log']->debug("ModuleInstaller.php->disable_copy(): backup_path=".$backup_path);
  2236. if(file_exists($backup_path)){
  2237. //since the file exists, then we want do an md5 of the install version and the file system version
  2238. $from = str_replace('<basepath>', $this->base_dir, $cp['from']);
  2239. //if(is_file($from) && md5_file($from) == md5_file($cp['to'])){
  2240. //since the files are the same then we can safely move back from the -restore
  2241. //directory into the file system
  2242. $GLOBALS['log']->debug("DISABLE COPY:: FROM: ".$backup_path. " TO: ".$cp['to']);
  2243. $this->copy_path($backup_path, $cp['to']);
  2244. /*}else{
  2245. //since they are not equal then we need to prompt the user
  2246. }*/
  2247. }//fi
  2248. }//rof
  2249. }//fi
  2250. }//fi
  2251. }
  2252. public function reset_opcodes()
  2253. {
  2254. /* Bug 39354 - added function_exists check. Not optimal fix, but safe nonetheless.
  2255. * This is for the upgrade to 6.1 from pre 6.1, since the utils files haven't been updated to 6.1 when this is called,
  2256. * but this file has been updated to 6.1
  2257. */
  2258. if(function_exists('sugar_clean_opcodes')){
  2259. sugar_clean_opcodes();
  2260. }
  2261. }
  2262. /**
  2263. * BC implementation to provide specific calls to extensions
  2264. */
  2265. public function __call($name, $args)
  2266. {
  2267. $nameparts = explode('_', $name);
  2268. // name is something_something
  2269. if(count($nameparts) == 2 && isset($this->extensions[$nameparts[1]])) {
  2270. $ext = $this->extensions[$nameparts[1]];
  2271. switch($nameparts[0]) {
  2272. case 'enable':
  2273. return $this->enableExt($ext['section'], $ext['extdir']);
  2274. case 'disable':
  2275. return $this->disableExt($ext['section'], $ext['extdir']);
  2276. case 'install':
  2277. return $this->installExt($ext['section'], $ext['extdir']);
  2278. case 'uninstall':
  2279. return $this->uninstallExt($ext['section'], $ext['extdir']);
  2280. case 'rebuild':
  2281. return $this->rebuildExt($ext['extdir'], $ext['file']);
  2282. }
  2283. }
  2284. sugar_die("Unknown method ModuleInstaller::$name called");
  2285. }
  2286. }
  2287. function UpdateSystemTabs($action, $installed_modules){
  2288. require_once("modules/MySettings/TabController.php");
  2289. $controller = new TabController();
  2290. $isSystemTabsInDB = $controller->is_system_tabs_in_db();
  2291. if ($isSystemTabsInDB && !empty($installed_modules))
  2292. {
  2293. global $moduleList;
  2294. switch ($action)
  2295. {
  2296. case 'Restore' :
  2297. $currentTabs = $controller->get_system_tabs();
  2298. foreach ($installed_modules as $module)
  2299. {
  2300. if(in_array($module, $currentTabs)){
  2301. unset($currentTabs[$module]);
  2302. }
  2303. }
  2304. $controller->set_system_tabs($currentTabs);;
  2305. break;
  2306. case 'Add' :
  2307. $currentTabs = $controller->get_system_tabs();
  2308. foreach ($installed_modules as $module)
  2309. {
  2310. if(!in_array($module, $currentTabs)){
  2311. $currentTabs[$module] = $module;
  2312. }
  2313. }
  2314. $controller->set_system_tabs($currentTabs);
  2315. default:
  2316. break;
  2317. }
  2318. }
  2319. }