PageRenderTime 89ms CodeModel.GetById 3ms app.highlight 72ms RepoModel.GetById 1ms app.codeStats 1ms

/ModuleInstall/ModuleInstaller.php

https://github.com/vincentamari/SuperSweetAdmin
PHP | 2351 lines | 1891 code | 218 blank | 242 comment | 415 complexity | 3445fef26e0ea0d86f0b93e97bf6ec26 MD5 | raw file

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

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

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