PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ModuleInstall/ModuleInstaller.php

https://github.com/mikmagic/sugarcrm_dev
PHP | 2351 lines | 1891 code | 218 blank | 242 comment | 415 complexity | b30c2b24c43efb8d53b1a829b78f832d MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  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-2011 SugarCRM Inc.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it under
  8. * the terms of the GNU Affero General Public License version 3 as published by the
  9. * Free Software Foundation with the addition of the following permission added
  10. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  11. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  12. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License along with
  20. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  21. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22. * 02110-1301 USA.
  23. *
  24. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  25. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  26. *
  27. * The interactive user interfaces in modified source and object code versions
  28. * of this program must display Appropriate Legal Notices, as required under
  29. * Section 5 of the GNU Affero General Public License version 3.
  30. *
  31. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  32. * these Appropriate Legal Notices must retain the display of the "Powered by
  33. * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  34. * technical reasons, the Appropriate Legal Notices must display the words
  35. * "Powered by SugarCRM".
  36. ********************************************************************************/
  37. /*
  38. * ModuleInstaller - takes an installation package from files in the custom/Extension/X directories, and moves them into custom/X to install them.
  39. * If a directory has multiple files they are concatenated together.
  40. * Relevant directories (X) are Layoutdefs, Vardefs, Include (bean stuff), Language, TableDictionary (relationships)
  41. *
  42. * Installation steps that involve more than just copying files:
  43. * 1. installing custom fields - calls bean->custom_fields->addField
  44. * 2. installing relationships - calls createTableParams to build the relationship table, and createRelationshipMeta to add the relationship to the relationship table
  45. * 3. rebuilding the relationships - at almost the last step in install(), calls modules/Administration/RebuildRelationship.php
  46. * 4. repair indices - uses "modules/Administration/RepairIndex.php";
  47. */
  48. require_once('include/utils/progress_bar_utils.php');
  49. require_once('ModuleInstall/ModuleScanner.php');
  50. define('DISABLED_PATH', 'Disabled');
  51. class ModuleInstaller{
  52. var $modules = array();
  53. var $silent = false;
  54. var $base_dir = '';
  55. var $modulesInPackage = array();
  56. function ModuleInstaller(){
  57. $this->ms = new ModuleScanner();
  58. $this->modules = get_module_dir_list();
  59. $this->db = & DBManagerFactory::getInstance();
  60. }
  61. /*
  62. * 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
  63. * 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
  64. * and moduleList - and then calls ModuleInstaller->merge_files('Ext/Include', 'modules.ext.php', '', true) to merge the individual module files into a combined file
  65. * /custom/Extension/application/Ext/Include/modules.ext.php (which now contains a list of all $beanList, $beanFiles and $moduleList for all extension modules) -
  66. * this file modules.ext.php is included at the end of modules.php.
  67. *
  68. * 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.
  69. */
  70. function install($base_dir, $is_upgrade = false, $previous_version = ''){
  71. if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
  72. if(!empty($GLOBALS['sugar_config']['moduleInstaller']['packageScan'])){
  73. $this->ms->scanPackage($base_dir);
  74. if($this->ms->hasIssues()){
  75. $this->ms->displayIssues();
  76. sugar_cleanup(true);
  77. }
  78. }
  79. global $app_strings, $mod_strings;
  80. $this->base_dir = $base_dir;
  81. $total_steps = 5; //minimum number of steps with no tasks
  82. $current_step = 0;
  83. $tasks = array(
  84. 'pre_execute',
  85. 'install_copy',
  86. 'install_images',
  87. 'install_menus',
  88. 'install_dcactions',
  89. 'install_userpage',
  90. 'install_dashlets',
  91. 'install_administration',
  92. 'install_connectors',
  93. 'install_vardefs',
  94. 'install_layoutdefs',
  95. 'install_layoutfields',
  96. 'install_relationships',
  97. 'install_languages',
  98. 'install_logichooks',
  99. 'post_execute',
  100. 'reset_opcodes',
  101. );
  102. $total_steps += count($tasks);
  103. if(file_exists($this->base_dir . '/manifest.php')){
  104. if(!$this->silent){
  105. $current_step++;
  106. display_progress_bar('install', $current_step, $total_steps);
  107. echo '<div id ="displayLoglink" ><a href="#" onclick="document.getElementById(\'displayLog\').style.display=\'\'">'
  108. .$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
  109. }
  110. include($this->base_dir . '/manifest.php');
  111. if($is_upgrade && !empty($previous_version)){
  112. //check if the upgrade path exists
  113. if(!empty($upgrade_manifest)){
  114. if(!empty($upgrade_manifest['upgrade_paths'])){
  115. if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
  116. $installdefs = $upgrade_manifest['upgrade_paths'][$previous_version];
  117. }else{
  118. $errors[] = 'No Upgrade Path Found in manifest.';
  119. $this->abort($errors);
  120. }//fi
  121. }//fi
  122. }//fi
  123. }//fi
  124. $this->id_name = $installdefs['id'];
  125. $this->installdefs = $installdefs;
  126. $installed_modules = array();
  127. $tab_modules = array();
  128. if(isset($installdefs['beans'])){
  129. $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
  130. foreach($installdefs['beans'] as $bean){
  131. if(!empty($bean['module']) && !empty($bean['class']) && !empty($bean['path'])){
  132. $module = $bean['module'];
  133. $class = $bean['class'];
  134. $path = $bean['path'];
  135. $str .= "\$beanList['$module'] = '$class';\n";
  136. $str .= "\$beanFiles['$class'] = '$path';\n";
  137. if($bean['tab']){
  138. $str .= "\$moduleList[] = '$module';\n";
  139. $this->install_user_prefs($module, empty($bean['hide_by_default']));
  140. $tab_modules[] = $module;
  141. }else{
  142. $str .= "\$modules_exempt_from_availability_check['$module'] = '$module';\n";
  143. $str .= "\$modInvisList[] = '$module';\n";
  144. }
  145. $installed_modules[] = $module;
  146. }else{
  147. $errors[] = 'Bean array not well defined.';
  148. $this->abort($errors);
  149. }
  150. }
  151. $str.= "\n?>";
  152. if(!file_exists("custom/Extension/application/Ext/Include")){
  153. mkdir_recursive("custom/Extension/application/Ext/Include", true);
  154. }
  155. $out = sugar_fopen("custom/Extension/application/Ext/Include/$this->id_name.php", 'w');
  156. fwrite($out,$str);
  157. fclose($out);
  158. $this->rebuild_modules();
  159. }
  160. if(!$this->silent){
  161. $current_step++;
  162. update_progress_bar('install', $current_step, $total_steps);
  163. }
  164. foreach($tasks as $task){
  165. $this->$task();
  166. if(!$this->silent){
  167. $current_step++;
  168. update_progress_bar('install', $current_step, $total_steps);
  169. }
  170. }
  171. $this->install_beans($installed_modules);
  172. if(!$this->silent){
  173. $current_step++;
  174. update_progress_bar('install', $total_steps, $total_steps);
  175. }
  176. if(isset($installdefs['custom_fields'])){
  177. $this->log(translate('LBL_MI_IN_CUSTOMFIELD'));
  178. $this->install_custom_fields($installdefs['custom_fields']);
  179. }
  180. if(!$this->silent){
  181. $current_step++;
  182. update_progress_bar('install', $current_step, $total_steps);
  183. echo '</div>';
  184. }
  185. if(!$this->silent){
  186. $current_step++;
  187. update_progress_bar('install', $current_step, $total_steps);
  188. echo '</div>';
  189. }
  190. $selectedActions = array(
  191. 'clearTpls',
  192. 'clearJsFiles',
  193. 'clearDashlets',
  194. 'clearVardefs',
  195. 'clearJsLangFiles',
  196. 'rebuildAuditTables',
  197. 'repairDatabase',
  198. );
  199. VardefManager::clearVardef();
  200. global $beanList, $beanFiles, $moduleList;
  201. if (file_exists('custom/application/Ext/Include/modules.ext.php'))
  202. {
  203. include('custom/application/Ext/Include/modules.ext.php');
  204. }
  205. require_once("modules/Administration/upgrade_custom_relationships.php");
  206. upgrade_custom_relationships($installed_modules);
  207. $this->rebuild_all(true);
  208. require_once('modules/Administration/QuickRepairAndRebuild.php');
  209. $rac = new RepairAndClear();
  210. $rac->repairAndClearAll($selectedActions, $installed_modules,true, false);
  211. $this->rebuild_relationships();
  212. UpdateSystemTabs('Add',$tab_modules);
  213. //clear the unified_search_module.php file
  214. require_once('modules/Home/UnifiedSearchAdvanced.php');
  215. UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
  216. $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
  217. }else{
  218. die("No \$installdefs Defined In $this->base_dir/manifest.php");
  219. }
  220. }
  221. function install_user_prefs($module, $hide_from_user=false){
  222. UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, !$hide_from_user);
  223. UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, $hide_from_user);
  224. UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, $hide_from_user);
  225. }
  226. function uninstall_user_prefs($module){
  227. UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, true);
  228. UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, true);
  229. UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, true);
  230. }
  231. function pre_execute(){
  232. require_once($this->base_dir . '/manifest.php');
  233. if(isset($this->installdefs['pre_execute']) && is_array($this->installdefs['pre_execute'])){
  234. foreach($this->installdefs['pre_execute'] as $includefile){
  235. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  236. }
  237. }
  238. }
  239. function post_execute(){
  240. require_once($this->base_dir . '/manifest.php');
  241. if(isset($this->installdefs['post_execute']) && is_array($this->installdefs['post_execute'])){
  242. foreach($this->installdefs['post_execute'] as $includefile){
  243. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  244. }
  245. }
  246. }
  247. function pre_uninstall(){
  248. require_once($this->base_dir . '/manifest.php');
  249. if(isset($this->installdefs['pre_uninstall']) && is_array($this->installdefs['pre_uninstall'])){
  250. foreach($this->installdefs['pre_uninstall'] as $includefile){
  251. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  252. }
  253. }
  254. }
  255. function post_uninstall(){
  256. require_once($this->base_dir . '/manifest.php');
  257. if(isset($this->installdefs['post_uninstall']) && is_array($this->installdefs['post_uninstall'])){
  258. foreach($this->installdefs['post_uninstall'] as $includefile){
  259. require_once(str_replace('<basepath>', $this->base_dir, $includefile));
  260. }
  261. }
  262. }
  263. /*
  264. * 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
  265. * (specified as from and to in the manifest), replacing <basepath> by the base_dir value passed in to install.
  266. */
  267. function install_copy(){
  268. if(isset($this->installdefs['copy'])){
  269. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
  270. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore" );
  271. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  272. foreach($this->installdefs['copy'] as $cp){
  273. $GLOBALS['log']->debug("Copying ..." . $cp['from']. " to " .$cp['to'] );
  274. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
  275. //$this->copy_path($cp['from'], $cp['to']);
  276. $this->copy_path($cp['from'], $cp['to'], $backup_path);
  277. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  278. }
  279. //here we should get the module list again as we could have copied something to the modules dir
  280. $this->modules = get_module_dir_list();
  281. }
  282. }
  283. function uninstall_copy(){
  284. if(!empty($this->installdefs['copy'])){
  285. foreach($this->installdefs['copy'] as $cp){
  286. $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
  287. $cp['from'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['from']));
  288. $GLOBALS['log']->debug('Unlink ' . $cp['to']);
  289. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
  290. //rmdir_recursive($cp['to']);
  291. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
  292. $this->uninstall_new_files($cp, $backup_path);
  293. $this->copy_path($backup_path, $cp['to'], $backup_path, true);
  294. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  295. }
  296. $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore");
  297. if(file_exists($backup_path))
  298. rmdir_recursive($backup_path);
  299. }
  300. }
  301. /**
  302. * Removes any files that were added by the loaded module. If the files already existed prior to install
  303. * it will be handled by copy_path with the uninstall parameter.
  304. *
  305. */
  306. function uninstall_new_files($cp, $backup_path){
  307. $zip_files = $this->dir_get_files($cp['from'],$cp['from']);
  308. $backup_files = $this->dir_get_files($backup_path, $backup_path);
  309. foreach($zip_files as $k=>$v){
  310. //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
  311. if(!isset($backup_files[$k])){
  312. $to = $cp['to'] . $k;
  313. //if it's not a sugar file then we remove it otherwise we can't restor it
  314. if(!$this->ms->sugarFileExists($to)){
  315. $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting file ' . $to);
  316. if(file_exists($to)) {
  317. unlink($to);
  318. }
  319. }else{
  320. $GLOBALS['log']->fatal('ModuleInstaller[uninstall_new_file] Could not remove file ' . $to . ' as no backup file was found to restore to');
  321. }
  322. }
  323. }
  324. //lets check if the directory is empty if it is we will delete it as well
  325. $files_remaining = $this->dir_file_count($cp['to']);
  326. if(file_exists($cp['to']) && $files_remaining == 0){
  327. $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting directory ' . $cp['to']);
  328. rmdir_recursive($cp['to']);
  329. }
  330. }
  331. function install_dashlets(){
  332. if(isset($this->installdefs['dashlets'])){
  333. foreach($this->installdefs['dashlets'] as $cp){
  334. $this->log(translate('LBL_MI_IN_DASHLETS') . $cp['name']);
  335. $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
  336. $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
  337. $GLOBALS['log']->debug("Installing Dashlet " . $cp['name'] . "..." . $cp['from'] );
  338. if(!file_exists($path)){
  339. mkdir_recursive($path, true);
  340. }
  341. copy_recursive($cp['from'] , $path);
  342. }
  343. include('modules/Administration/RebuildDashlets.php');
  344. }
  345. }
  346. function uninstall_dashlets(){
  347. if(isset($this->installdefs['dashlets'])){
  348. foreach($this->installdefs['dashlets'] as $cp){
  349. $this->log(translate('LBL_MI_UN_DASHLETS') . $cp['name']);
  350. $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
  351. $GLOBALS['log']->debug('Unlink ' .$path);
  352. if (file_exists($path))
  353. rmdir_recursive($path);
  354. }
  355. include('modules/Administration/RebuildDashlets.php');
  356. }
  357. }
  358. function install_images(){
  359. if(isset($this->installdefs['image_dir'])){
  360. $this->log( translate('LBL_MI_IN_IMAGES') );
  361. $this->copy_path($this->installdefs['image_dir'] , 'custom/themes');
  362. }
  363. }
  364. function install_menus(){
  365. if(isset($this->installdefs['menu'])){
  366. $this->log(translate('LBL_MI_IN_MENUS'));
  367. foreach($this->installdefs['menu'] as $menu){
  368. $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
  369. $GLOBALS['log']->debug("Installing Menu ..." . $menu['from']. " for " .$menu['to_module'] );
  370. $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
  371. if($menu['to_module'] == 'application'){
  372. $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
  373. }
  374. if(!file_exists($path)){
  375. mkdir_recursive($path, true);
  376. }
  377. copy_recursive($menu['from'] , $path . '/'. $this->id_name . '.php');
  378. }
  379. $this->rebuild_menus();
  380. }
  381. }
  382. function uninstall_menus(){
  383. if(isset($this->installdefs['menu'])){
  384. $this->log(translate('LBL_MI_UN_MENUS'));
  385. foreach($this->installdefs['menu'] as $menu){
  386. $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
  387. $GLOBALS['log']->debug("Uninstalling Menu ..." . $menu['from']. " for " .$menu['to_module'] );
  388. $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
  389. if($menu['to_module'] == 'application'){
  390. $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
  391. }
  392. if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
  393. {
  394. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  395. }
  396. else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
  397. {
  398. rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
  399. }
  400. }
  401. $this->rebuild_menus();
  402. }
  403. }
  404. function install_dcactions(){
  405. if(isset($this->installdefs['dcaction'])){
  406. $this->log(translate('LBL_MI_IN_MENUS'));
  407. foreach($this->installdefs['dcaction'] as $action){
  408. $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
  409. $GLOBALS['log']->debug("Installing DCActions ..." . $action['from']);
  410. $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
  411. if(!file_exists($path)){
  412. mkdir_recursive($path, true);
  413. }
  414. copy_recursive($action['from'] , $path . '/'. $this->id_name . '.php');
  415. }
  416. $this->rebuild_dashletcontainers();
  417. }
  418. }
  419. function uninstall_dcactions(){
  420. if(isset($this->installdefs['dcaction'])){
  421. $this->log(translate('LBL_MI_UN_MENUS'));
  422. foreach($this->installdefs['dcaction'] as $action){
  423. $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
  424. $GLOBALS['log']->debug("Uninstalling DCActions ..." . $action['from'] );
  425. $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
  426. if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
  427. {
  428. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  429. }
  430. else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
  431. {
  432. rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
  433. }
  434. }
  435. $this->rebuild_dashletcontainers();
  436. }
  437. }
  438. function install_administration(){
  439. if(isset($this->installdefs['administration'])){
  440. $this->log(translate('LBL_MI_IN_ADMIN'));
  441. foreach($this->installdefs['administration'] as $administration){
  442. $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
  443. $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] );
  444. $path = 'custom/Extension/modules/Administration/Ext/Administration';
  445. if(!file_exists($path)){
  446. mkdir_recursive($path, true);
  447. }
  448. copy_recursive($administration['from'] , $path . '/'. $this->id_name . '.php');
  449. }
  450. $this->rebuild_administration();
  451. }
  452. }
  453. function uninstall_administration(){
  454. if(isset($this->installdefs['administration'])){
  455. $this->log(translate('LBL_MI_UN_ADMIN'));
  456. foreach($this->installdefs['administration'] as $administration){
  457. $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
  458. $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] );
  459. $path = 'custom/Extension/modules/Administration/Ext/Administration';
  460. if (sugar_is_file($path . '/'. $this->id_name . '.php', "w"))
  461. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  462. else if (sugar_is_file($path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php', "w"))
  463. rmdir_recursive( $path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php');
  464. }
  465. $this->rebuild_administration();
  466. }
  467. }
  468. function install_connectors(){
  469. if(isset($this->installdefs['connectors'])){
  470. foreach($this->installdefs['connectors'] as $cp){
  471. $this->log(translate('LBL_MI_IN_CONNECTORS') . $cp['name']);
  472. $dir = str_replace('_','/',$cp['name']);
  473. $cp['connector'] = str_replace('<basepath>', $this->base_dir, $cp['connector']);
  474. $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir. '/';
  475. $GLOBALS['log']->debug("Installing Connector " . $cp['name'] . "..." . $cp['connector'] );
  476. if(!file_exists($source_path)){
  477. mkdir_recursive($source_path, true);
  478. }
  479. copy_recursive($cp['connector'] , $source_path);
  480. //Install optional formatter code if it is specified
  481. if(!empty($cp['formatter'])) {
  482. $cp['formatter'] = str_replace('<basepath>', $this->base_dir, $cp['formatter']);
  483. $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir. '/';
  484. if(!file_exists($formatter_path)){
  485. mkdir_recursive($formatter_path, true);
  486. }
  487. copy_recursive($cp['formatter'] , $formatter_path);
  488. }
  489. }
  490. require_once('include/connectors/utils/ConnectorUtils.php');
  491. ConnectorUtils::installSource($cp['name']);
  492. }
  493. }
  494. function uninstall_connectors(){
  495. if(isset($this->installdefs['connectors'])){
  496. foreach($this->installdefs['connectors'] as $cp){
  497. $this->log(translate('LBL_MI_UN_CONNECTORS') . $cp['name']);
  498. $dir = str_replace('_','/',$cp['name']);
  499. $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir;
  500. $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir;
  501. $GLOBALS['log']->debug('Unlink ' .$source_path);
  502. rmdir_recursive($source_path);
  503. rmdir_recursive($formatter_path);
  504. }
  505. require_once('include/connectors/utils/ConnectorUtils.php');
  506. //ConnectorUtils::getConnectors(true);
  507. ConnectorUtils::uninstallSource($cp['name']);
  508. }
  509. }
  510. function install_userpage(){
  511. if(isset($this->installdefs['user_page'])){
  512. $this->log(translate('LBL_MI_IN_USER'));
  513. foreach($this->installdefs['user_page'] as $userpage){
  514. $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
  515. $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] );
  516. $path = 'custom/Extension/modules/Users/Ext/UserPage';
  517. if(!file_exists($path)){
  518. mkdir_recursive($path, true);
  519. }
  520. copy_recursive($userpage['from'] , $path . '/'. $this->id_name . '.php');
  521. }
  522. $this->rebuild_userpage();
  523. }
  524. }
  525. function uninstall_userpage(){
  526. if(isset($this->installdefs['user_page'])){
  527. $this->log(translate('LBL_MI_UN_USER') );
  528. foreach($this->installdefs['user_page'] as $userpage){
  529. $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
  530. $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] );
  531. $path = 'custom/Extension/modules/Users/Ext/UserPage';
  532. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  533. }
  534. $this->rebuild_userpage();
  535. }
  536. }
  537. /*
  538. * ModuleInstaller->install_vardefs uses the vardefs section of the installdefs and copies from the 'from' path (replacing <basepath> as usual) to either
  539. * custom/Extension/modules/<module>/Ext/Vardefs or custom/Extension/<module>/Ext/Vardefs if the 'to_module' value in the installdefs is set to 'application'.
  540. * Finally rebuild_vardefs() is used to merge /Ext/Vardefs into vardefs.ext.php
  541. */
  542. function install_vardefs(){
  543. if(isset($this->installdefs['vardefs'])){
  544. $this->log(translate('LBL_MI_IN_VAR') );
  545. foreach($this->installdefs['vardefs'] as $vardefs){
  546. $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
  547. $this->install_vardef($vardefs['from'], $vardefs['to_module'], $this->id_name);
  548. }
  549. $this->rebuild_vardefs();
  550. }
  551. }
  552. function uninstall_vardefs(){
  553. if(isset($this->installdefs['vardefs'])){
  554. $this->log(translate('LBL_MI_UN_VAR') );
  555. foreach($this->installdefs['vardefs'] as $vardefs){
  556. $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
  557. $GLOBALS['log']->debug("Uninstalling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']);
  558. $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs';
  559. if($vardefs['to_module'] == 'application'){
  560. $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs';
  561. }
  562. if(file_exists($path . '/'. $this->id_name . '.php'))
  563. {
  564. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  565. }
  566. else if(file_exists($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'))
  567. {
  568. rmdir_recursive($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
  569. }
  570. else if (file_exists($path . '/'. basename($vardefs['from'] )))
  571. {
  572. rmdir_recursive( $path . '/'. basename($vardefs['from'] ));
  573. }
  574. else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from'])))
  575. {
  576. rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from']));
  577. }
  578. }
  579. $this->rebuild_vardefs();
  580. }
  581. }
  582. function install_vardef($from, $to_module){
  583. $GLOBALS['log']->debug("Installing Vardefs ..." . $from . " for " .$to_module);
  584. $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs';
  585. if($to_module == 'application'){
  586. $path ='custom/Extension/' . $to_module. '/Ext/Vardefs';
  587. }
  588. if(!file_exists($path)){
  589. mkdir_recursive($path, true);
  590. }
  591. copy_recursive($from , $path.'/'. basename($from));
  592. }
  593. /*
  594. * ModuleInstaller->install_layoutdefs installs the $layout_defs variable (subpanel definitions) from Ext/Layoutdefs to the to_module location of
  595. * custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs/<$module>.php. before calling rebuild_layoutdefs which merge_files Ext/Layoutdefs/, 'layoutdefs.ext.php'. Note that this is not used for the viewdefs in the metadata directory - they are installed through the install_copy() operation that just takes the contents of the module directory and places it in the /modules area.
  596. */
  597. function install_layoutdefs(){
  598. if(isset($this->installdefs['layoutdefs'])){
  599. $this->log(translate('LBL_MI_IN_SUBPANEL') );
  600. foreach($this->installdefs['layoutdefs'] as $layoutdefs){
  601. $layoutdefs['from'] = str_replace('<basepath>', $this->base_dir, $layoutdefs['from']);
  602. $this->install_layoutdef($layoutdefs['from'], $layoutdefs['to_module'], $this->id_name);
  603. }
  604. $this->rebuild_layoutdefs();
  605. }
  606. }
  607. function uninstall_layoutdefs(){
  608. if(isset($this->installdefs['layoutdefs'])){
  609. $this->log(translate('LBL_MI_UN_SUBPANEL') );
  610. foreach($this->installdefs['layoutdefs'] as $layoutdefs){
  611. $layoutdefs['from'] = str_replace('<basepath>', $this->base_dir, $layoutdefs['from']);
  612. $GLOBALS['log']->debug("Uninstalling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']);
  613. $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
  614. if($layoutdefs['to_module'] == 'application'){
  615. $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
  616. }
  617. if (file_exists($path . '/'. $this->id_name . '.php'))
  618. {
  619. rmdir_recursive( $path . '/'. $this->id_name . '.php');
  620. }
  621. else if (file_exists($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php'))
  622. {
  623. rmdir_recursive($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php');
  624. }
  625. else if (file_exists($path . '/'. basename($layoutdefs['from'] )))
  626. {
  627. rmdir_recursive( $path . '/'. basename($layoutdefs['from'] ));
  628. }
  629. else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from'])))
  630. {
  631. rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from']));
  632. }
  633. }
  634. $this->rebuild_layoutdefs();
  635. }
  636. }
  637. function install_layoutdef($from, $to_module){
  638. $GLOBALS['log']->debug("Installing Layout Defs ..." . $from . " for " .$to_module);
  639. $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs';
  640. if($to_module == 'application'){
  641. $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs';
  642. }
  643. if(!file_exists($path)){
  644. mkdir_recursive($path, true);
  645. }
  646. copy_recursive($from , $path.'/'. basename($from));
  647. }
  648. function install_languages()
  649. {
  650. $languages = array();
  651. if(isset($this->installdefs['language']))
  652. {
  653. $this->log(translate('LBL_MI_IN_LANG') );
  654. foreach($this->installdefs['language'] as $packs)
  655. {
  656. $modules[]=$packs['to_module'];
  657. $languages[$packs['language']] = $packs['language'];
  658. $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
  659. $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
  660. $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
  661. if($packs['to_module'] == 'application'){
  662. $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
  663. }
  664. if(!file_exists($path)){
  665. mkdir_recursive($path, true);
  666. }
  667. copy_recursive($packs['from'] , $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
  668. }
  669. $this->rebuild_languages($languages, $modules);
  670. }
  671. }
  672. function uninstall_languages(){
  673. $languages = array();
  674. if(isset($this->installdefs['language'])){
  675. $this->log(translate('LBL_MI_UN_LANG') );
  676. foreach($this->installdefs['language'] as $packs){
  677. $modules[]=$packs['to_module'];
  678. $languages[$packs['language']] = $packs['language'];
  679. $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
  680. $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
  681. $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
  682. if($packs['to_module'] == 'application'){
  683. $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
  684. }
  685. if (sugar_is_file($path.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
  686. rmdir_recursive( $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
  687. } else if (sugar_is_file($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
  688. rmdir_recursive($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w');
  689. }
  690. }
  691. $this->rebuild_languages($languages, $modules);
  692. }
  693. }
  694. // Functions for adding and removing logic hooks from uploaded files
  695. // 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
  696. /* The module hook definition should look like this:
  697. $installdefs = array(
  698. ... blah blah ...
  699. 'logic_hooks' => array(
  700. array('module' => 'Accounts',
  701. 'hook' => 'after_save',
  702. 'order' => 99,
  703. 'description' => 'Account sample logic hook',
  704. 'file' => 'modules/Sample/sample_account_logic_hook_file.php',
  705. 'class' => 'SampleLogicClass',
  706. 'function' => 'accountAfterSave',
  707. ),
  708. ),
  709. ... blah blah ...
  710. );
  711. */
  712. function install_logichooks() {
  713. // Since the logic hook files get copied over with the rest of the module directory, we just need to enable them
  714. $this->enable_logichooks();
  715. }
  716. function uninstall_logichooks() {
  717. // Since the logic hook files get removed with the rest of the module directory, we just need to disable them
  718. $this->disable_logichooks();
  719. }
  720. function enable_logichooks() {
  721. if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
  722. return;
  723. }
  724. foreach($this->installdefs['logic_hooks'] as $hook ) {
  725. check_logic_hook_file($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function']));
  726. }
  727. }
  728. function disable_logichooks() {
  729. if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
  730. return;
  731. }
  732. foreach($this->installdefs['logic_hooks'] as $hook ) {
  733. remove_logic_hook($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function']));
  734. }
  735. }
  736. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  737. function copy_path($from, $to, $backup_path='', $uninstall=false){
  738. //function copy_path($from, $to){
  739. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  740. $to = str_replace('<basepath>', $this->base_dir, $to);
  741. if(!$uninstall) {
  742. $from = str_replace('<basepath>', $this->base_dir, $from);
  743. $GLOBALS['log']->debug('Copy ' . $from);
  744. }
  745. else {
  746. $from = str_replace('<basepath>', $backup_path, $from);
  747. //$GLOBALS['log']->debug('Restore ' . $from);
  748. }
  749. $from = clean_path($from);
  750. $to = clean_path($to);
  751. $dir = dirname($to);
  752. //there are cases where if we need to create a directory in the root directory
  753. if($dir == '.' && is_dir($from)){
  754. $dir = $to;
  755. }
  756. if(!sugar_is_dir($dir, 'instance'))
  757. mkdir_recursive($dir, true);
  758. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  759. if(empty($backup_path)) {
  760. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  761. if(!copy_recursive($from, $to)){
  762. die('Failed to copy ' . $from. ' ' . $to);
  763. }
  764. /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  765. }
  766. elseif(!$this->copy_recursive_with_backup($from, $to, $backup_path, $uninstall)){
  767. die('Failed to copy ' . $from. ' to ' . $to);
  768. }
  769. /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
  770. }
  771. function install_custom_fields($fields){
  772. global $beanList, $beanFiles;
  773. include('include/modules.php');
  774. require_once('modules/DynamicFields/FieldCases.php');
  775. foreach($fields as $field){
  776. $installed = false;
  777. if(isset($beanList[ $field['module']])){
  778. $class = $beanList[ $field['module']];
  779. if(!isset($field['ext4']))$field['ext4'] = '';
  780. if(!isset($field['mass_update']))$field['mass_update'] = 0;
  781. if(!isset($field['duplicate_merge']))$field['duplicate_merge'] = 0;
  782. if(!isset($field['help']))$field['help'] = '';
  783. if(file_exists($beanFiles[$class])){
  784. require_once($beanFiles[$class]);
  785. $mod = new $class();
  786. $installed = true;
  787. $fieldObject = get_widget($field['type']);
  788. $fieldObject->populateFromRow($field);
  789. $mod->custom_fields->use_existing_labels = true;
  790. $mod->custom_fields->addFieldObject($fieldObject);
  791. }
  792. }
  793. if(!$installed){
  794. $GLOBALS['log']->debug('Could not install custom field ' . $field['name'] . ' for module ' . $field['module'] . ': Module does not exist');
  795. }
  796. }
  797. }
  798. function uninstall_custom_fields($fields){
  799. global $beanList, $beanFiles;
  800. require_once('modules/DynamicFields/DynamicField.php');
  801. $dyField = new DynamicField();
  802. foreach($fields as $field){
  803. $class = $beanList[ $field['module']];
  804. if(file_exists($beanFiles[$class])){
  805. require_once($beanFiles[$class]);
  806. $mod = new $class();
  807. $dyField->bean = $mod;
  808. $dyField->module = $field['module'];
  809. $dyField->deleteField($field['name']);
  810. }
  811. }
  812. }
  813. /*
  814. * ModuleInstaller->install_relationships calls install_relationship for every file included in the module package that defines a relationship, and then
  815. * writes a custom/Extension/application/Ext/TableDictionary/$module.php file containing an include_once for every relationship metadata file passed to install_relationship.
  816. * 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
  817. * everything in 'Ext/TableDictionary/' into 'tabledictionary.ext.php'
  818. */
  819. function install_relationships ()
  820. {
  821. if (isset ( $this->installdefs [ 'relationships' ] ))
  822. {
  823. $this->log ( translate ( 'LBL_MI_IN_RELATIONSHIPS' ) ) ;
  824. $str = "<?php \n //WARNING: The contents of this file are auto-generated\n" ;
  825. $save_table_dictionary = false ;
  826. if (! file_exists ( "custom/Extension/application/Ext/TableDictionary" ))
  827. {
  828. mkdir_recursive ( "custom/Extension/application/Ext/TableDictionary", true ) ;
  829. }
  830. foreach ( $this->installdefs [ 'relationships' ] as $key => $relationship )
  831. {
  832. $filename = basename ( $relationship [ 'meta_data' ] ) ;
  833. $this->copy_path ( $relationship [ 'meta_data' ], 'custom/metadata/' . $filename ) ;
  834. $this->install_relationship ( 'custom/metadata/' . $filename ) ;
  835. $save_table_dictionary = true ;
  836. if (! empty ( $relationship [ 'module_vardefs' ] ))
  837. {
  838. $relationship [ 'module_vardefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_vardefs' ] ) ;
  839. $this->install_vardef ( $relationship [ 'module_vardefs' ], $relationship [ 'module' ] ) ;
  840. }
  841. if (! empty ( $relationship [ 'module_layoutdefs' ] ))
  842. {
  843. $relationship [ 'module_layoutdefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_layoutdefs' ] ) ;
  844. $this->install_layoutdef ( $relationship [ 'module_layoutdefs' ], $relationship [ 'module' ] ) ;
  845. }
  846. $relName = strpos($filename, "MetaData") !== false ? substr($filename, 0, strlen($filename) - 12) : $filename;
  847. $out = sugar_fopen ( "custom/Extension/application/Ext/TableDictionary/$relName.php", 'w' ) ;
  848. fwrite ( $out, $str . "include('custom/metadata/$filename');\n\n?>" ) ;
  849. fclose ( $out ) ;
  850. }
  851. $this->rebuild_vardefs () ;
  852. $this->rebuild_layoutdefs () ;
  853. if ($save_table_dictionary)
  854. {
  855. $this->rebuild_tabledictionary () ;
  856. }
  857. }
  858. }
  859. /*
  860. * Install_relationship obtains a set of relationship definitions from the filename passed in as a parameter.
  861. * For each definition it calls db->createTableParams to build the relationships table if it does not exist,
  862. * and SugarBean::createRelationshipMeta to add the relationship into the 'relationships' table.
  863. */
  864. function install_relationship($file)
  865. {
  866. $_REQUEST['moduleInstaller'] = true;
  867. if(!file_exists($file))
  868. {
  869. $GLOBALS['log']->debug( 'File does not exists : '.$file);
  870. return;
  871. }
  872. include($file);
  873. $rel_dictionary = $dictionary;
  874. foreach ($rel_dictionary as $rel_name => $rel_data)
  875. {
  876. $table = ''; // table is actually optional
  877. // check if we have a table definition - not all relationships require a join table
  878. if ( isset( $rel_data[ 'table' ] ) )
  879. {
  880. $table = $rel_data[ 'table' ];
  881. if(!$this->db->tableExists($table))
  882. {
  883. $this->db->createTableParams($table, $rel_data[ 'fields' ], $rel_data[ 'indices' ]);
  884. }
  885. }
  886. if(!$this->silent)
  887. $GLOBALS['log']->debug("Processing relationship meta for ". $rel_name."...");
  888. SugarBean::createRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
  889. Relationship::delete_cache();
  890. if(!$this->silent)
  891. $GLOBALS['log']->debug( 'done<br>');
  892. }
  893. }
  894. function install_layoutfields() {
  895. if (!empty ( $this->installdefs [ 'layoutfields' ] ))
  896. {
  897. foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
  898. {
  899. if (!empty($fieldSet['additional_fields']))
  900. {
  901. $this->addFieldsToLayout($fieldSet['additional_fields']);
  902. }
  903. }
  904. }
  905. }
  906. function uninstall_layoutfields() {
  907. if (!empty ( $this->installdefs [ 'layoutfields' ] ))
  908. {
  909. foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
  910. {
  911. if (!empty($fieldSet['additional_fields']))
  912. {
  913. $this->removeFieldsFromLayout($fieldSet['additional_fields']);
  914. }
  915. }
  916. }
  917. }
  918. function uninstall_relationship($file, $rel_dictionary = null){
  919. if ($rel_dictionary == null)
  920. {
  921. if(!file_exists($file)){
  922. $GLOBALS['log']->debug( 'File does not exists : '.$file);
  923. return;
  924. }
  925. include($file);
  926. $rel_dictionary = $dictionary;
  927. }
  928. foreach ($rel_dictionary as $rel_name => $rel_data)
  929. {
  930. if (!empty($rel_data['table'])){
  931. $table = $rel_data['table'];
  932. }
  933. else{
  934. $table = ' One-to-Many ';
  935. }
  936. if ($this->db->tableExists($table) && isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
  937. {
  938. SugarBean::removeRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
  939. $this->db->dropTableName($table);
  940. if(!$this->silent) $this->log( translate('LBL_MI_UN_RELATIONSHIPS_DROP') . $table);
  941. }
  942. //Delete Layout defs
  943. // check to see if we have any vardef or layoutdef entries to remove - must have a relationship['module'] parameter if we do
  944. if (!isset($rel_data[ 'module' ]))
  945. $mods = array(
  946. $rel_data['relationships'][$rel_name]['lhs_module'],
  947. $rel_data['relationships'][$rel_name]['rhs_module'],
  948. );
  949. else
  950. $mods = array($rel_data[ 'module' ]);
  951. $filename = "$rel_name.php";
  952. foreach($mods as $mod) {
  953. if ($mod != 'application' ) {
  954. $basepath = "custom/Extension/modules/$mod/Ext/";
  955. } else {
  956. $basepath = "custom/Extension/application/Ext/";
  957. }
  958. foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
  959. //remove any vardefs
  960. $path = $basepath . "Vardefs/$fn" ;
  961. if (file_exists( $path ))
  962. rmdir_recursive( $path );
  963. //remove any layoutdefs
  964. $path = $basepath . "Layoutdefs/$fn" ;
  965. if( file_exists( $path ))
  966. {
  967. rmdir_recursive( $path );
  968. }
  969. }
  970. }
  971. foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
  972. // remove the table dictionary extension
  973. if ( file_exists("custom/Extension/application/Ext/TableDictionary/$fn"))
  974. unlink("custom/Extension/application/Ext/TableDictionary/$fn");
  975. if (file_exists("custom/metadata/{$rel_name}MetaData.php"))
  976. unlink( "custom/metadata/{$rel_name}MetaData.php" );
  977. }
  978. }
  979. }
  980. function uninstall_relationships($include_studio_relationships = false){
  981. $relationships = array();
  982. //Find and remove studio created relationships.
  983. global $beanList, $beanFiles, $dictionary;
  984. //Load up the custom relationship definitions.
  985. if(file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')){
  986. include('custom/application/Ext/TableDictionary/tabledictionary.ext.php');
  987. }
  988. //Find all the relatioships/relate fields involving this module.
  989. $rels_to_remove = array();
  990. foreach($beanList as $mod => $bean) {
  991. VardefManager::loadVardef($mod, $bean);
  992. //We can skip modules that are in this package as they will be removed anyhow
  993. if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields']))
  994. {
  995. $field_defs = $dictionary[$bean]['fields'];
  996. foreach($field_defs as $field => $def)
  997. {
  998. //Weed out most fields first
  999. if (isset ($def['type']))
  1000. {
  1001. //Custom relationships created in the relationship editor
  1002. if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']]))
  1003. {
  1004. $rel_name = $def['relationship'];
  1005. $rel_def = $dictionary[$rel_name]['relationships'][$rel_name];
  1006. //Check against mods to be removed.
  1007. foreach($this->modulesInPackage as $removed_mod) {
  1008. if ($rel_def['lhs_module'] == $removed_mod || $rel_def['rhs_module'] == $removed_mod )
  1009. {
  1010. $dictionary[$rel_name]['from_studio'] = true;
  1011. $relationships[$rel_name] = $dictionary[$rel_name];
  1012. }
  1013. }
  1014. }
  1015. //Custom "relate" fields created in studio also need to be removed
  1016. if ($def['type'] == 'relate' && isset($def['module'])) {
  1017. foreach($this->modulesInPackage as $removed_mod) {
  1018. if ($def['module'] == $removed_mod)
  1019. {
  1020. require_once 'modules/ModuleBuilder/Module/StudioModule.php' ;
  1021. $studioMod = new StudioModule ( $mod );
  1022. $studioMod->removeFieldFromLayouts( $field );
  1023. if (isset($def['custom_module'])) {
  1024. require_once ('modules/DynamicFields/DynamicField.php') ;
  1025. require_once ($beanFiles [ $bean ]) ;
  1026. $seed = new $bean ( ) ;
  1027. $df = new DynamicField ( $mod ) ;
  1028. $df->setup ( $seed ) ;
  1029. //Need to load the entire field_meta_data for some field types
  1030. $field_obj = $df->getFieldWidget($mod, $field);
  1031. $field_obj->delete ( $df ) ;
  1032. }
  1033. }
  1034. }
  1035. }
  1036. }
  1037. }
  1038. }
  1039. }
  1040. $this->uninstall_relationship(null, $relationships);
  1041. if(isset($this->installdefs['relationships'])) {
  1042. $relationships = $this->installdefs['relationships'];
  1043. $this->log(translate('LBL_MI_UN_RELATIONSHIPS') );
  1044. foreach($relationships as $relationship)
  1045. {
  1046. // remove the metadata entry
  1047. $filename = basename ( $relationship['meta_data'] );
  1048. $pathname = (file_exists("custom/metadata/$filename")) ? "custom/metadata/$filename" : "metadata/$filename" ;
  1049. if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
  1050. $this->uninstall_relationship( $pathname );
  1051. if (file_exists($pathname))
  1052. unlink( $pathname );
  1053. }
  1054. }
  1055. if (file_exists("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php"))
  1056. unlink("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php");
  1057. Relationship::delete_cache();
  1058. $this->rebuild_tabledictionary();
  1059. }
  1060. function uninstall($base_dir){
  1061. if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
  1062. global $app_strings;
  1063. $total_steps = 5; //min steps with no tasks
  1064. $current_step = 0;
  1065. $this->base_dir = $base_dir;
  1066. $tasks = array(
  1067. 'pre_uninstall',
  1068. 'uninstall_relationships',
  1069. 'uninstall_copy',
  1070. 'uninstall_dcactions',
  1071. 'uninstall_menus',
  1072. 'uninstall_dashlets',
  1073. 'uninstall_userpage',
  1074. 'uninstall_administration',
  1075. 'uninstall_connectors',
  1076. 'uninstall_vardefs',
  1077. 'uninstall_layoutdefs',
  1078. 'uninstall_layoutfields',
  1079. 'uninstall_languages',
  1080. 'uninstall_logichooks',
  1081. 'post_uninstall',
  1082. );
  1083. $total_steps += count($tasks); //now the real number of steps
  1084. if(file_exists($this->base_dir . '/manifest.php')){
  1085. if(!$this->silent){
  1086. $current_step++;
  1087. display_progress_bar('install', $current_step, $total_steps);
  1088. echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
  1089. }
  1090. global $moduleList;
  1091. include($this->base_dir . '/manifest.php');
  1092. $this->installdefs = $installdefs;
  1093. $this->id_name = $this->installdefs['id'];
  1094. $installed_modules = array();
  1095. if(isset($this->installdefs['beans'])){
  1096. foreach($this->installdefs['beans'] as $bean){
  1097. $installed_modules[] = $bean['module'];
  1098. $this->uninstall_user_prefs($bean['module']);
  1099. }
  1100. $this->modulesInPackage = $installed_modules;
  1101. $this->uninstall_beans($installed_modules);
  1102. $this->uninstall_customizations($installed_modules);
  1103. if(!$this->silent){
  1104. $current_step++;
  1105. update_progress_bar('install', $total_steps, $total_steps);
  1106. }
  1107. if (sugar_is_file("custom/Extension/application/Ext/Include/$this->id_name.php", 'w'))
  1108. rmdir_recursive("custom/Extension/application/Ext/Include/$this->id_name.php");
  1109. else if(sugar_is_file("custom/Extension/application/Ext/Include/" . DISABLED_PATH . "/$this->id_name.php", 'w'))
  1110. rmdir_recursive("custom/Extension/application/Ext/Include/" . DISABLED_PATH . "/$this->id_name.php");
  1111. $this->rebuild_modules();
  1112. }
  1113. if(!$this->silent){
  1114. $current_step++;
  1115. update_progress_bar('install', $current_step, $total_steps);
  1116. }
  1117. foreach($tasks as $task){
  1118. $this->$task();
  1119. if(!$this->silent){
  1120. $current_step++;
  1121. update_progress_bar('install', $current_step, $total_steps);
  1122. }
  1123. }
  1124. if(isset($installdefs['custom_fields']) && (isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])){
  1125. $this->log(translate('LBL_MI_UN_CUSTOMFIELD'));
  1126. $this->uninstall_custom_fields($installdefs['custom_fields']);
  1127. }
  1128. if(!$this->silent){
  1129. $current_step++;
  1130. update_progress_b

Large files files are truncated, but you can click here to view the full file