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.
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.
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
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
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.
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.
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 ********************************************************************************/
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)
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";
53 require_once('include/utils/progress_bar_utils.php');
55 require_once('ModuleInstall/ModuleScanner.php');
56 define('DISABLED_PATH', 'Disabled');
58 class ModuleInstaller{
59 var $modules = array();
62 var $modulesInPackage = array();
64 function ModuleInstaller(){
65 $this->ms = new ModuleScanner();
66 $this->modules = get_module_dir_list();
67 $this->db = & DBManagerFactory::getInstance();
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.
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.
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();
90 global $app_strings, $mod_strings;
91 $this->base_dir = $base_dir;
92 $total_steps = 5; //minimum number of steps with no tasks
102 'install_administration',
103 'install_connectors',
105 'install_layoutdefs',
106 'install_layoutfields',
107 'install_relationships',
109 'install_logichooks',
114 $total_steps += count($tasks);
115 if(file_exists($this->base_dir . '/manifest.php')){
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">';
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];
131 $errors[] = 'No Upgrade Path Found in manifest.';
132 $this->abort($errors);
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'];
149 $str .= "\$beanList['$module'] = '$class';\n";
150 $str .= "\$beanFiles['$class'] = '$path';\n";
152 $str .= "\$moduleList[] = '$module';\n";
153 $this->install_user_prefs($module, empty($bean['hide_by_default']));
154 $tab_modules[] = $module;
156 $str .= "\$modules_exempt_from_availability_check['$module'] = '$module';\n";
157 $str .= "\$modInvisList[] = '$module';\n";
159 $installed_modules[] = $module;
161 $errors[] = 'Bean array not well defined.';
162 $this->abort($errors);
166 if(!file_exists("custom/Extension/application/Ext/Include")){
167 mkdir_recursive("custom/Extension/application/Ext/Include", true);
169 $out = sugar_fopen("custom/Extension/application/Ext/Include/$this->id_name.php", 'w');
172 $this->rebuild_modules();
176 update_progress_bar('install', $current_step, $total_steps);
179 foreach($tasks as $task){
183 update_progress_bar('install', $current_step, $total_steps);
186 $this->install_beans($installed_modules);
189 update_progress_bar('install', $total_steps, $total_steps);
191 if(isset($installdefs['custom_fields'])){
192 $this->log(translate('LBL_MI_IN_CUSTOMFIELD'));
193 $this->install_custom_fields($installdefs['custom_fields']);
197 update_progress_bar('install', $current_step, $total_steps);
202 update_progress_bar('install', $current_step, $total_steps);
205 $selectedActions = array(
211 'rebuildAuditTables',
214 VardefManager::clearVardef();
215 global $beanList, $beanFiles, $moduleList;
216 if (file_exists('custom/application/Ext/Include/modules.ext.php'))
218 include('custom/application/Ext/Include/modules.ext.php');
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);
229 //clear the unified_search_module.php file
230 require_once('modules/Home/UnifiedSearchAdvanced.php');
231 UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
233 $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
235 die("No \$installdefs Defined In $this->base_dir/manifest.php");
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);
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);
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));
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));
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));
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));
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.
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 */
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();
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']);
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 */
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);
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.
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)) {
347 $GLOBALS['log']->fatal('ModuleInstaller[uninstall_new_file] Could not remove file ' . $to . ' as no backup file was found to restore to');
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']);
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);
371 copy_recursive($cp['from'] , $path);
373 include('modules/Administration/RebuildDashlets.php');
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);
387 include('modules/Administration/RebuildDashlets.php');
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');
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';
410 if(!file_exists($path)){
411 mkdir_recursive($path, true);
414 copy_recursive($menu['from'] , $path . '/'. $this->id_name . '.php');
416 $this->rebuild_menus();
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';
430 if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
432 rmdir_recursive( $path . '/'. $this->id_name . '.php');
434 else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
436 rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
439 $this->rebuild_menus();
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);
453 copy_recursive($action['from'] , $path . '/'. $this->id_name . '.php');
455 $this->rebuild_dashletcontainers();
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'))
468 rmdir_recursive( $path . '/'. $this->id_name . '.php');
470 else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
472 rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
475 $this->rebuild_dashletcontainers();
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);
490 copy_recursive($administration['from'] , $path . '/'. $this->id_name . '.php');
492 $this->rebuild_administration();
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');
508 $this->rebuild_administration();
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);
523 copy_recursive($cp['connector'] , $source_path);
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);
532 copy_recursive($cp['formatter'] , $formatter_path);
535 require_once('include/connectors/utils/ConnectorUtils.php');
536 ConnectorUtils::installSource($cp['name']);
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);
551 require_once('include/connectors/utils/ConnectorUtils.php');
552 //ConnectorUtils::getConnectors(true);
553 ConnectorUtils::uninstallSource($cp['name']);
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);
568 copy_recursive($userpage['from'] , $path . '/'. $this->id_name . '.php');
570 $this->rebuild_userpage();
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');
583 $this->rebuild_userpage();
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
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);
599 $this->rebuild_vardefs();
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';
612 if(file_exists($path . '/'. $this->id_name . '.php'))
614 rmdir_recursive( $path . '/'. $this->id_name . '.php');
616 else if(file_exists($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'))
618 rmdir_recursive($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
620 else if (file_exists($path . '/'. basename($vardefs['from'] )))
622 rmdir_recursive( $path . '/'. basename($vardefs['from'] ));
624 else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from'])))
626 rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from']));
629 $this->rebuild_vardefs();
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';
638 if(!file_exists($path)){
639 mkdir_recursive($path, true);
641 copy_recursive($from , $path.'/'. basename($from));
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.
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);
655 $this->rebuild_layoutdefs();
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';
668 if (file_exists($path . '/'. $this->id_name . '.php'))
670 rmdir_recursive( $path . '/'. $this->id_name . '.php');
672 else if (file_exists($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php'))
674 rmdir_recursive($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php');
676 else if (file_exists($path . '/'. basename($layoutdefs['from'] )))
678 rmdir_recursive( $path . '/'. basename($layoutdefs['from'] ));
680 else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from'])))
682 rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from']));
685 $this->rebuild_layoutdefs();
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';
694 if(!file_exists($path)){
695 mkdir_recursive($path, true);
697 copy_recursive($from , $path.'/'. basename($from));
700 function install_languages()
702 $languages = array();
703 if(isset($this->installdefs['language']))
705 $this->log(translate('LBL_MI_IN_LANG') );
706 foreach($this->installdefs['language'] as $packs)
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';
717 if(!file_exists($path)){
718 mkdir_recursive($path, true);
720 copy_recursive($packs['from'] , $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
722 $this->rebuild_languages($languages, $modules);
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';
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');
746 $this->rebuild_languages($languages, $modules);
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(
756 'logic_hooks' => array(
757 array('module' => 'Accounts',
758 'hook' => 'after_save',
760 'description' => 'Account sample logic hook',
761 'file' => 'modules/Sample/sample_account_logic_hook_file.php',
762 'class' => 'SampleLogicClass',
763 'function' => 'accountAfterSave',
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();
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();
779 function enable_logichooks() {
780 if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
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']));
791 function disable_logichooks() {
792 if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
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']));
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);
809 $from = str_replace('<basepath>', $this->base_dir, $from);
810 $GLOBALS['log']->debug('Copy ' . $from);
813 $from = str_replace('<basepath>', $backup_path, $from);
814 //$GLOBALS['log']->debug('Restore ' . $from);
816 $from = clean_path($from);
817 $to = clean_path($to);
820 //there are cases where if we need to create a directory in the root directory
821 if($dir == '.' && is_dir($from)){
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);
832 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
834 elseif(!$this->copy_recursive_with_backup($from, $to, $backup_path, $uninstall)){
835 die('Failed to copy ' . $from. ' to ' . $to);
837 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
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){
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'] = '';
853 if(file_exists($beanFiles[$class])){
854 require_once($beanFiles[$class]);
857 $fieldObject = get_widget($field['type']);
858 $fieldObject->populateFromRow($field);
859 $mod->custom_fields->use_existing_labels = true;
860 $mod->custom_fields->addFieldObject($fieldObject);
864 $GLOBALS['log']->debug('Could not install custom field ' . $field['name'] . ' for module ' . $field['module'] . ': Module does not exist');
869 function uninstall_custom_fields($fields){
870 global $beanList, $beanFiles;
871 require_once('modules/DynamicFields/DynamicField.php');
872 $dyField = new DynamicField();
874 foreach($fields as $field){
875 $class = $beanList[ $field['module']];
876 if(file_exists($beanFiles[$class])){
877 require_once($beanFiles[$class]);
879 $dyField->bean = $mod;
880 $dyField->module = $field['module'];
881 $dyField->deleteField($field['name']);
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'
892 function install_relationships ()
894 if (isset ( $this->installdefs [ 'relationships' ] ))
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 ;
900 if (! file_exists ( "custom/Extension/application/Ext/TableDictionary" ))
902 mkdir_recursive ( "custom/Extension/application/Ext/TableDictionary", true ) ;
905 foreach ( $this->installdefs [ 'relationships' ] as $key => $relationship )
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 ;
912 if (! empty ( $relationship [ 'module_vardefs' ] ))
914 $relationship [ 'module_vardefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_vardefs' ] ) ;
915 $this->install_vardef ( $relationship [ 'module_vardefs' ], $relationship [ 'module' ] ) ;
918 if (! empty ( $relationship [ 'module_layoutdefs' ] ))
920 $relationship [ 'module_layoutdefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_layoutdefs' ] ) ;
921 $this->install_layoutdef ( $relationship [ 'module_layoutdefs' ], $relationship [ 'module' ] ) ;
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?>" ) ;
932 $this->rebuild_vardefs () ;
933 $this->rebuild_layoutdefs () ;
934 if ($save_table_dictionary)
936 $this->rebuild_tabledictionary () ;
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.
947 function install_relationship($file)
949 $_REQUEST['moduleInstaller'] = true;
950 if(!file_exists($file))
952 $GLOBALS['log']->debug( 'File does not exists : '.$file);
956 $rel_dictionary = $dictionary;
957 foreach ($rel_dictionary as $rel_name => $rel_data)
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' ] ) )
963 $table = $rel_data[ 'table' ];
965 if(!$this->db->tableExists($table))
967 $this->db->createTableParams($table, $rel_data[ 'fields' ], $rel_data[ 'indices' ]);
972 $GLOBALS['log']->debug("Processing relationship meta for ". $rel_name."...");
973 SugarBean::createRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
974 Relationship::delete_cache();
976 $GLOBALS['log']->debug( 'done<br>');
980 function install_layoutfields() {
981 if (!empty ( $this->installdefs [ 'layoutfields' ] ))
983 foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
985 if (!empty($fieldSet['additional_fields']))
987 $this->addFieldsToLayout($fieldSet['additional_fields']);
993 function uninstall_layoutfields() {
994 if (!empty ( $this->installdefs [ 'layoutfields' ] ))
996 foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
998 if (!empty($fieldSet['additional_fields']))
1000 $this->removeFieldsFromLayout($fieldSet['additional_fields']);
1006 function uninstall_relationship($file, $rel_dictionary = null){
1007 if ($rel_dictionary == null)
1009 if(!file_exists($file)){
1010 $GLOBALS['log']->debug( 'File does not exists : '.$file);
1014 $rel_dictionary = $dictionary;
1017 foreach ($rel_dictionary as $rel_name => $rel_data)
1019 if (!empty($rel_data['table'])){
1020 $table = $rel_data['table'];
1023 $table = ' One-to-Many ';
1026 if ($this->db->tableExists($table) && isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
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);
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' ]))
1037 $rel_data['relationships'][$rel_name]['lhs_module'],
1038 $rel_data['relationships'][$rel_name]['rhs_module'],
1041 $mods = array($rel_data[ 'module' ]);
1043 $filename = "$rel_name.php";
1045 foreach($mods as $mod) {
1046 if ($mod != 'application' ) {
1047 $basepath = "custom/Extension/modules/$mod/Ext/";
1049 $basepath = "custom/Extension/application/Ext/";
1052 foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") as $fn) {
1053 //remove any vardefs
1054 $path = $basepath . "Vardefs/$fn" ;
1055 if (file_exists( $path ))
1056 rmdir_recursive( $path );
1058 //remove any layoutdefs
1059 $path = $basepath . "Layoutdefs/$fn" ;
1060 if( file_exists( $path ))
1062 rmdir_recursive( $path );
1067 foreach (array($filename , "custom" . $filename, $rel_name ."_". $mod. ".php") 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");
1072 if (file_exists("custom/metadata/{$rel_name}MetaData.php"))
1073 unlink( "custom/metadata/{$rel_name}MetaData.php" );
1078 function uninstall_relationships($include_studio_relationships = false){
1079 $relationships = array();
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');
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']))
1094 $field_defs = $dictionary[$bean]['fields'];
1095 foreach($field_defs as $field => $def)
1097 //Weed out most fields first
1098 if (isset ($def['type']))
1100 //Custom relationships created in the relationship editor
1101 if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']]))
1103 $rel_name = $def['relationship'];
1105 $rel_def = $dictionary[$rel_name]['relationships'][$rel_name];
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 )
1111 $dictionary[$rel_name]['from_studio'] = true;
1112 $relationships[$rel_name] = $dictionary[$rel_name];
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)
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 ) ;
1144 $this->uninstall_relationship(null, $relationships);
1146 if(isset($this->installdefs['relationships'])) {
1147 $relationships = $this->installdefs['relationships'];
1148 $this->log(translate('LBL_MI_UN_RELATIONSHIPS') );
1149 foreach($relationships as $relationship)
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 );
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();
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
1175 $this->base_dir = $base_dir;
1178 'uninstall_relationships',
1180 'uninstall_dcactions',
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',
1193 $total_steps += count($tasks); //now the real number of steps
1194 if(file_exists($this->base_dir . '/manifest.php')){
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">';
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'])){
1208 foreach($this->installdefs['beans'] as $bean){
1210 $installed_modules[] = $bean['module'];
1211 $this->uninstall_user_prefs($bean['module']);
1213 $this->modulesInPackage = $installed_modules;
1214 $this->uninstall_beans($installed_modules);
1215 $this->uninstall_customizations($installed_modules);
1218 update_progress_bar('install', $total_steps, $total_steps);
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");
1225 $this->rebuild_modules();
1229 update_progress_bar('install', $current_step, $total_steps);
1233 foreach($tasks as $task){
1237 update_progress_bar('install', $current_step, $total_steps);
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']);
1246 update_progress_bar('install', $current_step, $total_steps);
1249 //since we are passing $silent = true to rebuildAll() in that method it will set $this->silent = true, so
1250 //we need to save the setting to set it back after rebuildAll() completes.
1251 $silentBak = $this->silent;
1252 $this->rebuild_all(true);
1253 $this->silent = $silentBak;
1255 //#27877, If the request from MB redeploy a custom module , we will not remove the ACL actions for this package.
1256 if( !isset($_REQUEST['action']) || $_REQUEST['action']!='DeployPackage' ){
1257 $this->remove_acl_actions();
1263 update_progress_bar('install', $current_step, $total_steps);
1267 UpdateSystemTabs('Restore',$installed_modules);
1269 //clear the unified_search_module.php file
1270 require_once('modules/Home/UnifiedSearchAdvanced.php');
1271 UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile();
1273 $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
1275 update_progress_bar('install', $total_steps, $total_steps);
1278 die("No manifest.php Defined In $this->base_dir/manifest.php");
1282 function rebuild_languages($languages, $modules=""){
1283 foreach($languages as $language=>$value){
1284 $this->log(translate('LBL_MI_REBUILDING') . " Language...$language");
1285 $this->merge_files('Ext/Language/', $language.'.lang.ext.php', $language);
1287 foreach($modules as $module){
1288 LanguageManager::clearLanguageCache($module, $language);
1292 sugar_cache_reset();
1296 function rebuild_vardefs(){
1297 $this->log(translate('LBL_MI_REBUILDING') . " Vardefs...");
1298 $this->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
1299 sugar_cache_reset();
1302 function rebuild_layoutdefs(){
1303 $this->log(translate('LBL_MI_REBUILDING') . " Layoutdefs...");
1304 $this->merge_files('Ext/Layoutdefs/', 'layoutdefs.ext.php');
1308 function rebuild_menus(){
1309 $this->log(translate('LBL_MI_REBUILDING') . " Menus...");
1310 $this->merge_files('Ext/Menus/', 'menu.ext.php');
1313 function rebuild_dashletcontainers(){
1314 $this->log(translate('LBL_MI_REBUILDING') . " DC Actions...");
1315 $this->merge_files('Ext/DashletContainer/Containers/', 'dcactions.ext.php');
1318 function rebuild_modules(){
1319 $this->log(translate('LBL_MI_REBUILDING') . " Modules...");
1320 $this->merge_files('Ext/Include/', 'modules.ext.php', '', true);
1323 function rebuild_administration(){
1324 $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION'));
1325 $this->merge_files('Ext/Administration/', 'administration.ext.php');
1327 function rebuild_userpage(){
1328 $this->log(translate('LBL_MI_REBUILDING') . " User Page " . translate('LBL_MI_SECTION'));
1329 $this->merge_files('Ext/UserPage/', 'userpage.ext.php');
1331 function rebuild_tabledictionary(){
1332 $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION'));
1333 $this->merge_files('Ext/TableDictionary/', 'tabledictionary.ext.php');
1336 function rebuild_relationships() {
1337 if(!$this->silent) echo translate('LBL_MI_REBUILDING') . ' Relationships';
1338 $_REQUEST['silent'] = true;
1340 include('include/modules.php');
1341 include("modules/Administration/RebuildRelationship.php");
1344 function remove_acl_actions() {
1345 global $beanFiles, $beanList, $current_user;
1346 include('include/modules.php');
1347 include("modules/ACL/remove_actions.php");
1351 * Wrapper call to modules/Administration/RepairIndex.php
1353 function repair_indices() {
1354 global $current_user,$beanFiles,$dictionary;
1355 $this->log(translate('LBL_MI_REPAIR_INDICES'));
1356 $_REQUEST['silent'] = true; // local var flagging echo'd output in repair script
1357 $_REQUEST['mode'] = 'execute'; // flag to just go ahead and run the script
1358 include("modules/Administration/RepairIndex.php");
1362 * Rebuilds the extension files found in custom/Extension
1363 * @param boolean $silent
1365 function rebuild_all($silent=false){
1366 if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
1367 $this->silent=$silent;
1368 global $sugar_config;
1370 //Check for new module extensions
1371 $this->rebuild_modules();
1373 $this->rebuild_languages($sugar_config['languages']);
1374 $this->rebuild_vardefs();
1375 $this->rebuild_layoutdefs();
1376 $this->rebuild_menus();
1377 $this->rebuild_dashletcontainers();
1378 $this->rebuild_userpage();
1379 $this->rebuild_administration();
1380 $this->rebuild_relationships();
1381 $this->rebuild_tabledictionary();
1382 //$this->repair_indices();
1383 $this->reset_opcodes();
1384 sugar_cache_reset();
1388 * ModuleInstaller->merge_files runs over the list of all modules already installed in /modules. For each $module it reads the contents of every file in
1389 * custom/Extension/modules/$module/<path> (_override files last) and concatenates them to custom/modules/$module/<path>/<file>.
1390 * Then it does the same thing in custom/Extension/application/<path>, concatenating those files and copying the result to custom/application/<path>/<file>
1392 function merge_files($path, $name, $filter = '', $application = false){
1394 $GLOBALS['log']->debug( get_class($this)."->merge_files() : merging module files in custom/Extension/modules/<module>/$path to custom/modules/<module>/$path$name");
1395 foreach($this->modules as $module){
1396 //$GLOBALS['log']->debug("Merging Files for: ".$module);
1397 //$GLOBALS['log']->debug("Merging Files for path: ".$path);
1398 $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1399 $extpath = "modules/$module/$path";
1400 $module_install = 'custom/Extension/'.$extpath;
1401 $shouldSave = false;
1402 if(is_dir($module_install)){
1403 $dir = dir($module_install);
1405 $override = array();
1406 while($entry = $dir->read()){
1407 if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
1408 && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
1410 if (substr($entry, 0, 9) == '_override') {
1411 $override[] = $entry;
1413 $file = file_get_contents($module_install . '/' . $entry);
1414 $GLOBALS['log']->debug(get_class($this)."->merge_files(): found {$module_install}{$entry}") ;
1415 $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1419 foreach ($override as $entry) {
1420 $file = file_get_contents($module_install . '/' . $entry);
1421 $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1424 $extension .= "\n?>";
1427 if(!file_exists("custom/$extpath")){
1428 mkdir_recursive("custom/$extpath", true);
1430 $out = sugar_fopen("custom/$extpath/$name", 'w');
1431 fwrite($out,$extension);
1434 if(file_exists("custom/$extpath/$name")){
1435 unlink("custom/$extpath/$name");
1442 $GLOBALS['log']->debug("Merging application files for $name in $path");
1443 //Now the application stuff
1444 $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1445 $extpath = "application/$path";
1446 $module_install = 'custom/Extension/'.$extpath;
1447 $shouldSave = false;
1448 if(is_dir($module_install)){
1449 $dir = dir($module_install);
1450 while($entry = $dir->read()){
1452 if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
1453 && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
1455 $file = file_get_contents($module_install . '/' . $entry);
1456 $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1460 $extension .= "\n?>";
1462 if(!file_exists("custom/$extpath")){
1463 mkdir_recursive("custom/$extpath", true);
1465 $out = sugar_fopen("custom/$extpath/$name", 'w');
1466 fwrite($out,$extension);
1469 if(file_exists("custom/$extpath/$name")){
1470 unlink("custom/$extpath/$name");
1477 * ModuleInstaller->install_beans runs through the list of beans given, instantiates each bean, calls bean->create_tables, and then calls SugarBean::createRelationshipMeta for the
1480 function install_beans($beans){
1481 include('include/modules.php');
1482 foreach($beans as $bean){
1483 $this->log( translate('LBL_MI_IN_BEAN') . " $bean");
1484 if(isset($beanList[$bean])){
1485 $class = $beanList[$bean];
1486 if(file_exists($beanFiles[$class])){
1487 require_once($beanFiles[$class]);
1488 $mod = new $class();
1490 if(is_subclass_of($mod, 'SugarBean') && $mod->disable_vardefs == false ){
1491 $GLOBALS['log']->debug( "Creating Tables Bean : $bean");
1492 $mod->create_tables();
1493 SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir);
1496 $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
1502 function uninstall_beans($beans){
1503 include('include/modules.php');
1504 foreach($beans as $bean){
1505 $this->log( translate('LBL_MI_UN_BEAN') . " $bean");
1506 if(isset($beanList[$bean])){
1507 $class = $beanList[$bean];
1509 if(file_exists($beanFiles[$class])){
1510 require_once($beanFiles[$class]);
1511 $mod = new $class();
1513 if(is_subclass_of($mod, 'SugarBean')){
1514 $GLOBALS['log']->debug( "Drop Tables : $bean");
1515 if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1516 $mod->drop_tables();
1519 $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
1526 * Remove any customizations made within Studio while the module was installed.
1528 function uninstall_customizations($beans){
1529 foreach($beans as $bean){
1531 'custom/modules/' . $bean,
1532 'custom/Extension/modules/' . $bean
1534 foreach($dirs as $dir)
1537 rmdir_recursive($dir);
1544 $GLOBALS['log']->debug('ModuleInstaller:'. $str);
1550 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:15:18 PM */
1551 function copy_recursive_with_backup( $source, $dest, $backup_path, $uninstall=false ) {
1552 if(is_file($source)) {
1554 $GLOBALS['log']->debug("Restoring ... " . $source. " to " .$dest );
1555 if(copy( $source, $dest)) {
1556 if(is_writable($dest))
1557 sugar_touch( $dest, filemtime($source) );
1558 return(unlink($source));
1561 $GLOBALS['log']->debug( "Can't restore file: " . $source );
1566 if(file_exists($dest)) {
1567 $rest = clean_path($backup_path."/$dest");
1568 if( !is_dir(dirname($rest)) )
1569 mkdir_recursive(dirname($rest), true);
1571 $GLOBALS['log']->debug("Backup ... " . $dest. " to " .$rest );
1572 if(copy( $dest, $rest)) {
1573 if(is_writable($rest))
1574 sugar_touch( $rest, filemtime($dest) );
1577 $GLOBALS['log']->debug( "Can't backup file: " . $dest );
1580 return( copy( $source, $dest ) );
1583 elseif(!is_dir($source)) {
1586 return(unlink($dest));
1588 //don't do anything we already cleaned up the files using uninstall_new_files
1596 if( !is_dir($dest) && !$uninstall){
1597 sugar_mkdir( $dest );
1602 $d = dir( $source );
1603 while( $f = $d->read() ){
1604 if( $f == "." || $f == ".." ){
1607 $status &= $this->copy_recursive_with_backup( "$source/$f", "$dest/$f", $backup_path, $uninstall );
1613 private function dir_get_files($path, $base_path){
1615 if(!is_dir($path))return $files;
1617 while ($e = $d->read()){
1618 //ignore invisible files . .. ._MACOSX
1619 if(substr($e, 0, 1) == '.')continue;
1620 if(is_file($path . '/' . $e))$files[str_replace($base_path , '', $path . '/' . $e)] = str_replace($base_path , '', $path . '/' . $e);
1621 if(is_dir($path . '/' . $e))$files = array_merge($files, $this->dir_get_files($path . '/' . $e, $base_path));
1628 private function dir_file_count($path){
1629 //if its a file then it has at least 1 file in the directory
1630 if(is_file($path)) return 1;
1631 if(!is_dir($path)) return 0;
1634 while ($e = $d->read()){
1635 //ignore invisible files . .. ._MACOSX
1636 if(substr($e, 0, 1) == '.')continue;
1637 if(is_file($path . '/' . $e))$count++;
1638 if(is_dir($path . '/' . $e))$count += $this->dir_file_count($path . '/' . $e);
1645 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:15:34 PM */
1649 * Static function which allows a module developer to abort their progress, pass in an array of errors and
1650 * redirect back to the main module loader page
1652 * @param errors an array of error messages which will be displayed on the
1653 * main module loader page once it is loaded.
1655 function abort($errors = array()){
1656 //set the errors onto the session so we can display them one the moduler loader page loads
1657 $_SESSION['MODULEINSTALLER_ERRORS'] = $errors;
1658 echo '<META HTTP-EQUIV="Refresh" content="0;url=index.php?module=Administration&action=UpgradeWizard&view=module">';
1660 //header('Location: index.php?module=Administration&action=UpgradeWizard&view=module');
1664 * Return the set of errors stored in the SESSION
1666 * @return an array of errors
1668 function getErrors(){
1669 if(!empty($_SESSION['MODULEINSTALLER_ERRORS'])){
1670 $errors = $_SESSION['MODULEINSTALLER_ERRORS'];
1671 unset($_SESSION['MODULEINSTALLER_ERRORS']);
1679 * Add any fields to the DetailView and EditView of the appropriate modules
1680 * Only add into deployed modules, as addFieldsToUndeployedLayouts has done this already for undeployed modules (and the admin might have edited the layouts already)
1681 * @param array $layoutAdditions An array of module => fieldname
1684 function addFieldsToLayout($layoutAdditions) {
1685 require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
1687 // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
1688 // In either case, we don't want to attempt to add a relate field to them
1689 // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
1690 $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
1692 foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
1694 if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
1696 foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
1698 $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
1699 $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
1700 $parser->addField ( array ( 'name' => $fieldName ) ) ;
1701 $parser->handleSave ( false ) ;
1708 function removeFieldsFromLayout($layoutAdditions) {
1709 require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
1711 // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
1712 // In either case, we don't want to attempt to add a relate field to them
1713 // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
1714 $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
1716 foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
1718 if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
1720 foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
1722 $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
1723 $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
1724 $parser->removeField ( $fieldName ) ;
1725 $parser->handleSave ( false ) ;
1733 //********** DISABLE/ENABLE FUNCTIONS
1735 function enable($base_dir, $is_upgrade = false, $previous_version = ''){
1736 global $app_strings;
1737 $this->base_dir = $base_dir;
1738 $total_steps = 3; //minimum number of steps with no tasks
1745 'enable_administration',
1747 'enable_layoutdefs',
1748 'enable_relationships',
1750 'enable_logichooks',
1753 $total_steps += count($tasks);
1754 if(file_exists($this->base_dir . '/manifest.php')){
1757 display_progress_bar('install', $current_step, $total_steps);
1758 echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
1761 require_once($this->base_dir . '/manifest.php');
1762 if($is_upgrade && !empty($previous_version)){
1763 //check if the upgrade path exists
1764 if(!empty($upgrade_manifest)){
1765 if(!empty($upgrade_manifest['upgrade_paths'])){
1766 if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
1767 $installdefs = $upgrade_manifest['upgrade_paths'][$previous_version];
1769 $errors[] = 'No Upgrade Path Found in manifest.';
1770 $this->abort($errors);
1775 $this->id_name = $installdefs['id'];
1776 $this->installdefs = $installdefs;
1777 $installed_modules = array();
1778 if(isset($installdefs['beans'])){
1779 foreach($this->installdefs['beans'] as $bean){
1780 $installed_modules[] = $bean['module'];
1782 if(!file_exists("custom/Extension/application/Ext/Include")){
1783 mkdir_recursive("custom/Extension/application/Ext/Include", true);
1785 if (file_exists("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php'))
1786 rename("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php',"custom/Extension/application/Ext/Include/$this->id_name.php");
1787 $this->rebuild_modules();
1791 update_progress_bar('install', $current_step, $total_steps);
1794 foreach($tasks as $task){
1798 update_progress_bar('install', $current_step, $total_steps);
1804 update_progress_bar('install', $current_step, $total_steps);
1807 UpdateSystemTabs('Add',$installed_modules);
1808 $GLOBALS['log']->debug('Complete');
1811 die("No \$installdefs Defined In $this->base_dir/manifest.php");
1815 function disable($base_dir){
1816 global $app_strings;
1817 $total_steps = 3; //min steps with no tasks
1819 $this->base_dir = $base_dir;
1825 'disable_administration',
1827 'disable_layoutdefs',
1828 'disable_relationships',
1829 'disable_languages',
1830 'disable_logichooks',
1833 $total_steps += count($tasks); //now the real number of steps
1834 if(file_exists($this->base_dir . '/manifest.php')){
1837 display_progress_bar('install', $current_step, $total_steps);
1838 echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
1841 require_once($this->base_dir . '/manifest.php');
1842 $this->installdefs = $installdefs;
1843 $this->id_name = $this->installdefs['id'];
1844 $installed_modules = array();
1845 if(isset($this->installdefs['beans'])){
1846 foreach($this->installdefs['beans'] as $bean){
1847 $installed_modules[] = $bean['module'];
1850 mkdir_recursive("custom/Extension/application/Ext/Include/".DISABLED_PATH, true);
1852 //Clear any older disabled version
1853 if (file_exists("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php'))
1854 rmdir_recursive("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php');
1856 if (file_exists("custom/Extension/application/Ext/Include/$this->id_name.php"))
1857 rename("custom/Extension/application/Ext/Include/$this->id_name.php", "custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php');
1858 $this->rebuild_modules();
1862 update_progress_bar('install', $current_step, $total_steps);
1864 foreach($tasks as $task){
1868 update_progress_bar('install', $current_step, $total_steps);
1873 update_progress_bar('install', $current_step, $total_steps);
1876 UpdateSystemTabs('Restore',$installed_modules);
1879 die("No manifest.php Defined In $this->base_dir/manifest.php");
1882 function enable_vardef($to_module){
1883 if(isset($this->installdefs['vardefs'])){
1884 foreach($this->installdefs['vardefs'] as $vardefs){
1885 $GLOBALS['log']->debug("Enabling Vardefs ..." .$to_module);
1886 $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs';
1887 if($to_module == 'application'){
1888 $path ='custom/Extension/' . $to_module. '/Ext/Vardefs';
1890 if(!file_exists($path)){
1891 mkdir_recursive($path, true);
1893 if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'))
1894 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
1895 if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from'])))
1896 rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from']));
1900 function enable_vardefs(){
1901 if(isset($this->installdefs['vardefs'])){
1902 foreach($this->installdefs['vardefs'] as $vardefs){
1903 $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
1904 $GLOBALS['log']->debug("Enabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']);
1905 $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs';
1906 if($vardefs['to_module'] == 'application'){
1907 $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs';
1909 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'))
1910 rename( $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
1912 if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from'])))
1913 rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from']));
1916 $this->rebuild_vardefs();
1919 function disable_vardefs(){
1920 $GLOBALS['log']->debug("Disabling Vardefs ".var_export($this->installdefs, true));
1921 if(isset($this->installdefs['vardefs'])){
1922 foreach($this->installdefs['vardefs'] as $vardefs){
1923 $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
1924 $GLOBALS['log']->debug("Disabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']);
1925 $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs';
1926 if($vardefs['to_module'] == 'application'){
1927 $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs';
1929 if(file_exists($path . '/'. $this->id_name . '.php')) {
1930 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1931 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
1933 if(file_exists($path . '/'. basename($vardefs['from'])))
1935 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1936 rename( $path . '/'. basename($vardefs['from']), $path . '/'.DISABLED_PATH.'/'.basename($vardefs['from']));
1939 $this->rebuild_vardefs();
1943 function enable_relationships(){
1944 if(isset($this->installdefs['relationships'])){
1945 $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1946 $save_table_dictionary = false;
1947 foreach($this->installdefs['relationships'] as $relationship){
1948 $filename =basename($relationship['meta_data']);
1950 $save_table_dictionary = true;
1951 $str .= "include_once('metadata/$filename');\n";
1952 if (empty($relationship['module']))
1955 if(!empty($relationship['module_vardefs'])){
1956 $this->enable_vardef($relationship['module']);
1958 if(!empty($relationship['module_layoutdefs'])){
1959 $this->enable_layoutdef($relationship['module']);
1962 $this->rebuild_vardefs();
1963 $this->rebuild_layoutdefs();
1964 if($save_table_dictionary){
1965 if(!file_exists("custom/Extension/application/Ext/TableDictionary")){
1966 mkdir_recursive("custom/Extension/application/Ext/TableDictionary", true);
1968 if (file_exists("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php"))
1969 rename("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/$this->id_name.php");
1970 $this->rebuild_tabledictionary();
1975 function disable_relationships($action = 'disable'){
1976 if(isset($this->installdefs['relationships'])){
1977 foreach($this->installdefs['relationships'] as $relationship){
1978 $filename = basename($relationship['meta_data']);
1979 $relName = substr($filename, -12) == "MetaData.php" ? substr($filename,0,strlen($filename) - 12) : "";
1980 if (empty($relationship['module']) && empty($relName))
1983 //remove the vardefs
1984 if (empty($relName))
1985 $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Vardefs';
1986 if(!empty($relationship['module']) && $relationship['module'] == 'application'){
1987 $path ='custom/Extension/' . $relationship['module']. '/Ext/Vardefs';
1989 if(!empty($relationship['module_vardefs']) && file_exists($path . '/'. $this->id_name . '.php')){
1990 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1991 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
1993 //remove the layoutdefs
1994 if ( !empty($relationship['module']) ) {
1995 $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Layoutdefs';
1996 if($relationship['module'] == 'application'){
1997 $path ='custom/Extension/' . $relationship['module']. '/Ext/Layoutdefs';
2001 if(!empty($relationship['module_layoutdefs']) && file_exists($path . '/'. $this->id_name . '.php')){
2002 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2003 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2007 if(file_exists("custom/Extension/application/Ext/TableDictionary/$this->id_name.php")){
2008 mkdir_recursive("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH, true);
2009 rename("custom/Extension/application/Ext/TableDictionary/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php");
2011 $this->rebuild_tabledictionary();
2012 $this->rebuild_vardefs();
2013 $this->rebuild_layoutdefs();
2017 function enable_layoutdefs(){
2018 if(isset($this->installdefs['layoutdefs'])){
2019 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
2020 $this->enable_layoutdef($layoutdefs['to_module'], $this->id_name);
2022 $this->rebuild_layoutdefs();
2025 function enable_layoutdef($to_module){
2026 $GLOBALS['log']->debug("Enabling Layout Defs ..." .$to_module);
2027 if(isset($this->installdefs['layoutdefs'])){
2028 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
2029 $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs';
2030 if($to_module == 'application'){
2031 $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs';
2033 if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'))
2035 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2037 if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from'])))
2039 rename($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']), $path . '/'. basename($layoutdefs['from']));
2045 function disable_layoutdefs(){
2046 if(isset($this->installdefs['layoutdefs'])){
2047 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
2048 $layoutdefs['from'] = str_replace('<basepath>', $this->base_dir, $layoutdefs['from']);
2049 $GLOBALS['log']->debug("Disabling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']);
2050 $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
2051 if($layoutdefs['to_module'] == 'application'){
2052 $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
2054 if (file_exists($path . '/'. $this->id_name . '.php'))
2056 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2057 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2058 }else if (file_exists($path . '/'. basename($layoutdefs['from'])))
2060 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2061 rename( $path . '/'. basename($layoutdefs['from']), $path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']));
2064 $this->rebuild_layoutdefs();
2068 function enable_menus(){
2069 if(isset($this->installdefs['menu'])){
2070 foreach($this->installdefs['menu'] as $menu){
2071 $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
2072 $GLOBALS['log']->debug("Enabling Menu ..." . $menu['from']. " for " .$menu['to_module'] );
2073 $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
2074 if($menu['to_module'] == 'application'){
2075 $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
2078 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){
2079 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2083 $this->rebuild_menus();
2088 function disable_menus(){
2089 if(isset($this->installdefs['menu'])){
2090 foreach($this->installdefs['menu'] as $menu){
2091 $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
2092 $GLOBALS['log']->debug("Disabling Menu ..." . $menu['from']. " for " .$menu['to_module'] );
2093 $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
2094 if($menu['to_module'] == 'application'){
2095 $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
2097 if (file_exists( $path . '/'. $this->id_name . '.php'))
2099 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2100 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2103 $this->rebuild_menus();
2107 function enable_administration(){
2108 if(isset($this->installdefs['administration'])){
2109 foreach($this->installdefs['administration'] as $administration){
2110 $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
2111 $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] );
2112 $path = 'custom/Extension/modules/Administration/Ext/Administration';
2114 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){
2115 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2118 $this->rebuild_administration();
2122 function disable_administration(){
2123 if(isset($this->installdefs['administration'])){
2124 foreach($this->installdefs['administration'] as $administration){
2125 $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
2126 $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] );
2127 $path = 'custom/Extension/modules/Administration/Ext/Administration';
2128 if (file_exists($path . '/'. $this->id_name . '.php'))
2130 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2131 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2134 $this->rebuild_administration();
2138 function enable_dashlets(){
2139 if(isset($this->installdefs['dashlets'])){
2140 foreach($this->installdefs['dashlets'] as $cp){
2141 $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
2142 $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
2143 $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
2144 $GLOBALS['log']->debug("Enabling Dashlet " . $cp['name'] . "..." . $cp['from'] );
2145 if (file_exists($disabled_path))
2147 rename($disabled_path, $path);
2150 include('modules/Administration/RebuildDashlets.php');
2155 function disable_dashlets(){
2156 if(isset($this->installdefs['dashlets'])){
2157 foreach($this->installdefs['dashlets'] as $cp){
2158 $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
2159 $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
2160 $GLOBALS['log']->debug('Disabling ' .$path);
2161 if (file_exists($path))
2163 mkdir_recursive('custom/modules/Home/'.DISABLED_PATH.'Dashlets/', true);
2164 rename( $path, $disabled_path);
2167 include('modules/Administration/RebuildDashlets.php');
2171 function enable_languages(){
2172 $languages = array();
2173 if(isset($this->installdefs['language'])){
2174 foreach($this->installdefs['language'] as $packs){
2175 $languages[$packs['language']] = $packs['language'];
2176 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
2177 $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
2178 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
2179 if($packs['to_module'] == 'application'){
2180 $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
2183 if(!file_exists($path)){
2184 mkdir_recursive($path, true);
2186 if (file_exists($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php'))
2187 rename($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
2189 $this->rebuild_languages($languages);
2193 function disable_languages(){
2194 $languages = array();
2195 if(isset($this->installdefs['language'])){
2196 foreach($this->installdefs['language'] as $packs){
2197 $languages[$packs['language']] = $packs['language'];
2198 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
2199 $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
2200 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
2201 if($packs['to_module'] == 'application'){
2202 $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
2204 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2205 if (file_exists($path.'/'.$packs['language'].'.'. $this->id_name . '.php'))
2206 rename($path.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php');
2209 $this->rebuild_languages($languages);
2213 function enable_userpage(){
2214 if(isset($this->installdefs['user_page'])){
2215 foreach($this->installdefs['user_page'] as $userpage){
2216 $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
2217 $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] );
2218 $path = 'custom/Extension/modules/Users/Ext/UserPage';
2219 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){
2220 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2224 $this->rebuild_userpage();
2228 function disable_userpage(){
2229 if(isset($this->installdefs['user_page'])){
2230 foreach($this->installdefs['user_page'] as $userpage){
2231 $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
2232 $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] );
2233 $path = 'custom/Extension/modules/Users/Ext/UserPage';
2234 if (file_exists( $path . '/'. $this->id_name . '.php')) {
2235 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2236 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2239 $this->rebuild_userpage();
2243 function enable_copy(){
2244 //copy files back onto file system. first perform md5 check to determine if anything has been modified
2245 //here we should just go through the files in the -restore directory and copy those back
2246 if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
2247 if(!empty($this->installdefs['copy'])){
2248 foreach($this->installdefs['copy'] as $cp){
2249 $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
2250 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
2252 //check if this file exists in the -restore directory
2253 if(file_exists($backup_path)){
2254 //since the file exists, then we want do an md5 of the install version and the file system version
2255 //if(is_file($backup_path) && md5_file($backup_path) == md5_file($cp['to'])){
2256 //since the files are the same then we can safely move back from the -restore
2257 //directory into the file system
2258 $GLOBALS['log']->debug("ENABLE COPY:: FROM: ".$cp['from']. " TO: ".$cp['to']);
2259 $this->copy_path($cp['from'], $cp['to']);
2261 //since they are not equal then we need to prompt the user
2269 function disable_copy(){
2270 //when we disable we want to copy the -restore files back into the file system
2271 //but we should check the version in the module install against the version on the file system
2272 //if they match then we can copy the file back, but otherwise we should ask the user.
2274 // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy()');
2275 if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
2276 // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy():mi_overwrite_files=true');
2277 if(!empty($this->installdefs['copy'])){
2278 // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy(): installdefs not empty');
2279 foreach($this->installdefs['copy'] as $cp){
2280 $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
2281 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); // bug 16966 tyoung - replaced missing assignment to $backup_path
2282 //check if this file exists in the -restore directory
2283 // $GLOBALS['log']->debug("ModuleInstaller.php->disable_copy(): backup_path=".$backup_path);
2284 if(file_exists($backup_path)){
2285 //since the file exists, then we want do an md5 of the install version and the file system version
2286 $from = str_replace('<basepath>', $this->base_dir, $cp['from']);
2288 //if(is_file($from) && md5_file($from) == md5_file($cp['to'])){
2289 //since the files are the same then we can safely move back from the -restore
2290 //directory into the file system
2291 $GLOBALS['log']->debug("DISABLE COPY:: FROM: ".$backup_path. " TO: ".$cp['to']);
2292 $this->copy_path($backup_path, $cp['to']);
2294 //since they are not equal then we need to prompt the user
2302 public function reset_opcodes()
2304 /* Bug 39354 - added function_exists check. Not optimal fix, but safe nonetheless.
2305 * This is for the upgrade to 6.1 from pre 6.1, since the utils files haven't been updated to 6.1 when this is called,
2306 * but this file has been updated to 6.1
2308 if(function_exists('sugar_clean_opcodes')){
2309 sugar_clean_opcodes();
2315 function UpdateSystemTabs($action, $installed_modules){
2316 require_once("modules/MySettings/TabController.php");
2317 $controller = new TabController();
2318 $isSystemTabsInDB = $controller->is_system_tabs_in_db();
2319 if ($isSystemTabsInDB && !empty($installed_modules))
2325 $currentTabs = $controller->get_system_tabs();
2326 foreach ($installed_modules as $module)
2328 if(in_array($module, $currentTabs)){
2329 unset($currentTabs[$module]);
2332 $controller->set_system_tabs($currentTabs);;
2335 $currentTabs = $controller->get_system_tabs();
2336 foreach ($installed_modules as $module)
2338 if(!in_array($module, $currentTabs)){
2339 $currentTabs[$module] = $module;
2342 $controller->set_system_tabs($currentTabs);