2 if(!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.
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 $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
229 UpdateSystemTabs('Add',$tab_modules);
232 die("No \$installdefs Defined In $this->base_dir/manifest.php");
237 function install_user_prefs($module, $hide_from_user=false){
238 UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, !$hide_from_user);
239 UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, $hide_from_user);
240 UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, $hide_from_user);
242 function uninstall_user_prefs($module){
243 UserPreference::updateAllUserPrefs('display_tabs', $module, '', true, true);
244 UserPreference::updateAllUserPrefs('hide_tabs', $module, '', true, true);
245 UserPreference::updateAllUserPrefs('remove_tabs', $module, '', true, true);
248 function pre_execute(){
249 require_once($this->base_dir . '/manifest.php');
250 if(isset($this->installdefs['pre_execute']) && is_array($this->installdefs['pre_execute'])){
251 foreach($this->installdefs['pre_execute'] as $includefile){
252 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
257 function post_execute(){
258 require_once($this->base_dir . '/manifest.php');
259 if(isset($this->installdefs['post_execute']) && is_array($this->installdefs['post_execute'])){
260 foreach($this->installdefs['post_execute'] as $includefile){
261 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
266 function pre_uninstall(){
267 require_once($this->base_dir . '/manifest.php');
268 if(isset($this->installdefs['pre_uninstall']) && is_array($this->installdefs['pre_uninstall'])){
269 foreach($this->installdefs['pre_uninstall'] as $includefile){
270 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
275 function post_uninstall(){
276 require_once($this->base_dir . '/manifest.php');
277 if(isset($this->installdefs['post_uninstall']) && is_array($this->installdefs['post_uninstall'])){
278 foreach($this->installdefs['post_uninstall'] as $includefile){
279 require_once(str_replace('<basepath>', $this->base_dir, $includefile));
285 * 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
286 * (specified as from and to in the manifest), replacing <basepath> by the base_dir value passed in to install.
288 function install_copy(){
289 if(isset($this->installdefs['copy'])){
290 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
291 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore" );
292 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
293 foreach($this->installdefs['copy'] as $cp){
294 $GLOBALS['log']->debug("Copying ..." . $cp['from']. " to " .$cp['to'] );
295 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
296 //$this->copy_path($cp['from'], $cp['to']);
297 $this->copy_path($cp['from'], $cp['to'], $backup_path);
298 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
300 //here we should get the module list again as we could have copied something to the modules dir
301 $this->modules = get_module_dir_list();
304 function uninstall_copy(){
305 if(!empty($this->installdefs['copy'])){
306 foreach($this->installdefs['copy'] as $cp){
307 $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
308 $cp['from'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['from']));
309 $GLOBALS['log']->debug('Unlink ' . $cp['to']);
310 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:11 PM */
311 //rmdir_recursive($cp['to']);
313 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
314 $this->uninstall_new_files($cp, $backup_path);
315 $this->copy_path($backup_path, $cp['to'], $backup_path, true);
316 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
318 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore");
319 if(file_exists($backup_path))
320 rmdir_recursive($backup_path);
326 * Removes any files that were added by the loaded module. If the files already existed prior to install
327 * it will be handled by copy_path with the uninstall parameter.
330 function uninstall_new_files($cp, $backup_path){
331 $zip_files = $this->dir_get_files($cp['from'],$cp['from']);
332 $backup_files = $this->dir_get_files($backup_path, $backup_path);
333 foreach($zip_files as $k=>$v){
334 //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
335 if(!isset($backup_files[$k])){
336 $to = $cp['to'] . $k;
337 //if it's not a sugar file then we remove it otherwise we can't restor it
338 if(!$this->ms->sugarFileExists($to)){
339 $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting file ' . $to);
342 $GLOBALS['log']->fatal('ModuleInstaller[uninstall_new_file] Could not remove file ' . $to . ' as no backup file was found to restore to');
346 //lets check if the directory is empty if it is we will delete it as well
347 $files_remaining = $this->dir_file_count($cp['to']);
348 if(file_exists($cp['to']) && $files_remaining == 0){
349 $GLOBALS['log']->debug('ModuleInstaller[uninstall_new_file] deleting directory ' . $cp['to']);
350 rmdir_recursive($cp['to']);
356 function install_dashlets(){
357 if(isset($this->installdefs['dashlets'])){
358 foreach($this->installdefs['dashlets'] as $cp){
359 $this->log(translate('LBL_MI_IN_DASHLETS') . $cp['name']);
360 $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
361 $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
362 $GLOBALS['log']->debug("Installing Dashlet " . $cp['name'] . "..." . $cp['from'] );
363 if(!file_exists($path)){
364 mkdir_recursive($path, true);
366 copy_recursive($cp['from'] , $path);
368 include('modules/Administration/RebuildDashlets.php');
373 function uninstall_dashlets(){
374 if(isset($this->installdefs['dashlets'])){
375 foreach($this->installdefs['dashlets'] as $cp){
376 $this->log(translate('LBL_MI_UN_DASHLETS') . $cp['name']);
377 $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
378 $GLOBALS['log']->debug('Unlink ' .$path);
379 if (file_exists($path))
380 rmdir_recursive($path);
382 include('modules/Administration/RebuildDashlets.php');
387 function install_images(){
388 if(isset($this->installdefs['image_dir'])){
389 $this->log( translate('LBL_MI_IN_IMAGES') );
390 $this->copy_path($this->installdefs['image_dir'] , 'custom/themes');
395 function install_menus(){
396 if(isset($this->installdefs['menu'])){
397 $this->log(translate('LBL_MI_IN_MENUS'));
398 foreach($this->installdefs['menu'] as $menu){
399 $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
400 $GLOBALS['log']->debug("Installing Menu ..." . $menu['from']. " for " .$menu['to_module'] );
401 $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
402 if($menu['to_module'] == 'application'){
403 $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
405 if(!file_exists($path)){
406 mkdir_recursive($path, true);
409 copy_recursive($menu['from'] , $path . '/'. $this->id_name . '.php');
411 $this->rebuild_menus();
415 function uninstall_menus(){
416 if(isset($this->installdefs['menu'])){
417 $this->log(translate('LBL_MI_UN_MENUS'));
418 foreach($this->installdefs['menu'] as $menu){
419 $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
420 $GLOBALS['log']->debug("Uninstalling Menu ..." . $menu['from']. " for " .$menu['to_module'] );
421 $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
422 if($menu['to_module'] == 'application'){
423 $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
425 if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
427 rmdir_recursive( $path . '/'. $this->id_name . '.php');
429 else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
431 rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
434 $this->rebuild_menus();
438 function install_dcactions(){
439 if(isset($this->installdefs['dcaction'])){
440 $this->log(translate('LBL_MI_IN_MENUS'));
441 foreach($this->installdefs['dcaction'] as $action){
442 $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
443 $GLOBALS['log']->debug("Installing DCActions ..." . $action['from']);
444 $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
445 if(!file_exists($path)){
446 mkdir_recursive($path, true);
448 copy_recursive($action['from'] , $path . '/'. $this->id_name . '.php');
450 $this->rebuild_dashletcontainers();
454 function uninstall_dcactions(){
455 if(isset($this->installdefs['dcaction'])){
456 $this->log(translate('LBL_MI_UN_MENUS'));
457 foreach($this->installdefs['dcaction'] as $action){
458 $action['from'] = str_replace('<basepath>', $this->base_dir, $action['from']);
459 $GLOBALS['log']->debug("Uninstalling DCActions ..." . $action['from'] );
460 $path = 'custom/Extension/application/Ext/DashletContainer/Containers';
461 if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w'))
463 rmdir_recursive( $path . '/'. $this->id_name . '.php');
465 else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w'))
467 rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
470 $this->rebuild_dashletcontainers();
474 function install_administration(){
475 if(isset($this->installdefs['administration'])){
476 $this->log(translate('LBL_MI_IN_ADMIN'));
477 foreach($this->installdefs['administration'] as $administration){
478 $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
479 $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] );
480 $path = 'custom/Extension/modules/Administration/Ext/Administration';
481 if(!file_exists($path)){
482 mkdir_recursive($path, true);
485 copy_recursive($administration['from'] , $path . '/'. $this->id_name . '.php');
487 $this->rebuild_administration();
491 function uninstall_administration(){
492 if(isset($this->installdefs['administration'])){
493 $this->log(translate('LBL_MI_UN_ADMIN'));
494 foreach($this->installdefs['administration'] as $administration){
495 $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
496 $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] );
497 $path = 'custom/Extension/modules/Administration/Ext/Administration';
498 if (sugar_is_file($path . '/'. $this->id_name . '.php', "w"))
499 rmdir_recursive( $path . '/'. $this->id_name . '.php');
500 else if (sugar_is_file($path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php', "w"))
501 rmdir_recursive( $path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php');
503 $this->rebuild_administration();
507 function install_connectors(){
508 if(isset($this->installdefs['connectors'])){
509 foreach($this->installdefs['connectors'] as $cp){
510 $this->log(translate('LBL_MI_IN_CONNECTORS') . $cp['name']);
511 $dir = str_replace('_','/',$cp['name']);
512 $cp['connector'] = str_replace('<basepath>', $this->base_dir, $cp['connector']);
513 $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir. '/';
514 $GLOBALS['log']->debug("Installing Connector " . $cp['name'] . "..." . $cp['connector'] );
515 if(!file_exists($source_path)){
516 mkdir_recursive($source_path, true);
518 copy_recursive($cp['connector'] , $source_path);
520 //Install optional formatter code if it is specified
521 if(!empty($cp['formatter'])) {
522 $cp['formatter'] = str_replace('<basepath>', $this->base_dir, $cp['formatter']);
523 $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir. '/';
524 if(!file_exists($formatter_path)){
525 mkdir_recursive($formatter_path, true);
527 copy_recursive($cp['formatter'] , $formatter_path);
530 require_once('include/connectors/utils/ConnectorUtils.php');
531 ConnectorUtils::installSource($cp['name']);
535 function uninstall_connectors(){
536 if(isset($this->installdefs['connectors'])){
537 foreach($this->installdefs['connectors'] as $cp){
538 $this->log(translate('LBL_MI_UN_CONNECTORS') . $cp['name']);
539 $dir = str_replace('_','/',$cp['name']);
540 $source_path = 'custom/modules/Connectors/connectors/sources/' . $dir;
541 $formatter_path = 'custom/modules/Connectors/connectors/formatters/' . $dir;
542 $GLOBALS['log']->debug('Unlink ' .$source_path);
543 rmdir_recursive($source_path);
544 rmdir_recursive($formatter_path);
546 require_once('include/connectors/utils/ConnectorUtils.php');
547 //ConnectorUtils::getConnectors(true);
548 ConnectorUtils::uninstallSource($cp['name']);
552 function install_userpage(){
553 if(isset($this->installdefs['user_page'])){
554 $this->log(translate('LBL_MI_IN_USER'));
555 foreach($this->installdefs['user_page'] as $userpage){
556 $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
557 $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] );
558 $path = 'custom/Extension/modules/Users/Ext/UserPage';
559 if(!file_exists($path)){
560 mkdir_recursive($path, true);
563 copy_recursive($userpage['from'] , $path . '/'. $this->id_name . '.php');
565 $this->rebuild_userpage();
569 function uninstall_userpage(){
570 if(isset($this->installdefs['user_page'])){
571 $this->log(translate('LBL_MI_UN_USER') );
572 foreach($this->installdefs['user_page'] as $userpage){
573 $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
574 $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] );
575 $path = 'custom/Extension/modules/Users/Ext/UserPage';
576 rmdir_recursive( $path . '/'. $this->id_name . '.php');
578 $this->rebuild_userpage();
583 * ModuleInstaller->install_vardefs uses the vardefs section of the installdefs and copies from the 'from' path (replacing <basepath> as usual) to either
584 * custom/Extension/modules/<module>/Ext/Vardefs or custom/Extension/<module>/Ext/Vardefs if the 'to_module' value in the installdefs is set to 'application'.
585 * Finally rebuild_vardefs() is used to merge /Ext/Vardefs into vardefs.ext.php
587 function install_vardefs(){
588 if(isset($this->installdefs['vardefs'])){
589 $this->log(translate('LBL_MI_IN_VAR') );
590 foreach($this->installdefs['vardefs'] as $vardefs){
591 $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
592 $this->install_vardef($vardefs['from'], $vardefs['to_module'], $this->id_name);
594 $this->rebuild_vardefs();
597 function uninstall_vardefs(){
598 if(isset($this->installdefs['vardefs'])){
599 $this->log(translate('LBL_MI_UN_VAR') );
600 foreach($this->installdefs['vardefs'] as $vardefs){
601 $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
602 $GLOBALS['log']->debug("Uninstalling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']);
603 $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs';
604 if($vardefs['to_module'] == 'application'){
605 $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs';
607 if(file_exists($path . '/'. $this->id_name . '.php'))
609 rmdir_recursive( $path . '/'. $this->id_name . '.php');
611 else if(file_exists($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'))
613 rmdir_recursive($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php');
615 else if (file_exists($path . '/'. basename($vardefs['from'] )))
617 rmdir_recursive( $path . '/'. basename($vardefs['from'] ));
619 else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from'])))
621 rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from']));
624 $this->rebuild_vardefs();
627 function install_vardef($from, $to_module){
628 $GLOBALS['log']->debug("Installing Vardefs ..." . $from . " for " .$to_module);
629 $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs';
630 if($to_module == 'application'){
631 $path ='custom/Extension/' . $to_module. '/Ext/Vardefs';
633 if(!file_exists($path)){
634 mkdir_recursive($path, true);
636 copy_recursive($from , $path.'/'. basename($from));
640 * ModuleInstaller->install_layoutdefs installs the $layout_defs variable (subpanel definitions) from Ext/Layoutdefs to the to_module location of
641 * 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.
643 function install_layoutdefs(){
644 if(isset($this->installdefs['layoutdefs'])){
645 $this->log(translate('LBL_MI_IN_SUBPANEL') );
646 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
647 $layoutdefs['from'] = str_replace('<basepath>', $this->base_dir, $layoutdefs['from']);
648 $this->install_layoutdef($layoutdefs['from'], $layoutdefs['to_module'], $this->id_name);
650 $this->rebuild_layoutdefs();
653 function uninstall_layoutdefs(){
654 if(isset($this->installdefs['layoutdefs'])){
655 $this->log(translate('LBL_MI_UN_SUBPANEL') );
656 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
657 $layoutdefs['from'] = str_replace('<basepath>', $this->base_dir, $layoutdefs['from']);
658 $GLOBALS['log']->debug("Uninstalling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']);
659 $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
660 if($layoutdefs['to_module'] == 'application'){
661 $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
663 if (file_exists($path . '/'. $this->id_name . '.php'))
665 rmdir_recursive( $path . '/'. $this->id_name . '.php');
667 else if (file_exists($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php'))
669 rmdir_recursive($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php');
671 else if (file_exists($path . '/'. basename($layoutdefs['from'] )))
673 rmdir_recursive( $path . '/'. basename($layoutdefs['from'] ));
675 else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from'])))
677 rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from']));
680 $this->rebuild_layoutdefs();
683 function install_layoutdef($from, $to_module){
684 $GLOBALS['log']->debug("Installing Layout Defs ..." . $from . " for " .$to_module);
685 $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs';
686 if($to_module == 'application'){
687 $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs';
689 if(!file_exists($path)){
690 mkdir_recursive($path, true);
692 copy_recursive($from , $path.'/'. basename($from));
695 function install_languages()
697 $languages = array();
698 if(isset($this->installdefs['language']))
700 $this->log(translate('LBL_MI_IN_LANG') );
701 foreach($this->installdefs['language'] as $packs)
703 $modules[]=$packs['to_module'];
704 $languages[$packs['language']] = $packs['language'];
705 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
706 $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
707 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
708 if($packs['to_module'] == 'application'){
709 $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
712 if(!file_exists($path)){
713 mkdir_recursive($path, true);
715 copy_recursive($packs['from'] , $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
717 $this->rebuild_languages($languages, $modules);
722 function uninstall_languages(){
723 $languages = array();
724 if(isset($this->installdefs['language'])){
725 $this->log(translate('LBL_MI_UN_LANG') );
726 foreach($this->installdefs['language'] as $packs){
727 $modules[]=$packs['to_module'];
728 $languages[$packs['language']] = $packs['language'];
729 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
730 $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
731 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
732 if($packs['to_module'] == 'application'){
733 $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
735 if (sugar_is_file($path.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
736 rmdir_recursive( $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
737 } else if (sugar_is_file($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w')) {
738 rmdir_recursive($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', 'w');
741 $this->rebuild_languages($languages, $modules);
746 // Functions for adding and removing logic hooks from uploaded files
747 // 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
748 /* The module hook definition should look like this:
749 $installdefs = array(
751 'logic_hooks' => array(
752 array('module' => 'Accounts',
753 'hook' => 'after_save',
755 'description' => 'Account sample logic hook',
756 'file' => 'modules/Sample/sample_account_logic_hook_file.php',
757 'class' => 'SampleLogicClass',
758 'function' => 'accountAfterSave',
764 function install_logichooks() {
765 // Since the logic hook files get copied over with the rest of the module directory, we just need to enable them
766 $this->enable_logichooks();
769 function uninstall_logichooks() {
770 // Since the logic hook files get removed with the rest of the module directory, we just need to disable them
771 $this->disable_logichooks();
774 function enable_logichooks() {
775 if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
781 foreach($this->installdefs['logic_hooks'] as $hook ) {
782 check_logic_hook_file($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function']));
786 function disable_logichooks() {
787 if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) {
792 foreach($this->installdefs['logic_hooks'] as $hook ) {
793 remove_logic_hook($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function']));
797 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
798 function copy_path($from, $to, $backup_path='', $uninstall=false){
799 //function copy_path($from, $to){
800 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
801 $to = str_replace('<basepath>', $this->base_dir, $to);
804 $from = str_replace('<basepath>', $this->base_dir, $from);
805 $GLOBALS['log']->debug('Copy ' . $from);
808 $from = str_replace('<basepath>', $backup_path, $from);
809 //$GLOBALS['log']->debug('Restore ' . $from);
811 $from = clean_path($from);
812 $to = clean_path($to);
815 //there are cases where if we need to create a directory in the root directory
816 if($dir == '.' && is_dir($from)){
819 if(!sugar_is_dir($dir, 'instance'))
820 mkdir_recursive($dir, true);
821 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
822 if(empty($backup_path)) {
823 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
824 if(!copy_recursive($from, $to)){
825 die('Failed to copy ' . $from. ' ' . $to);
827 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
829 elseif(!$this->copy_recursive_with_backup($from, $to, $backup_path, $uninstall)){
830 die('Failed to copy ' . $from. ' to ' . $to);
832 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:22:18 PM */
835 function install_custom_fields($fields){
836 global $beanList, $beanFiles;
837 include('include/modules.php');
838 require_once('modules/DynamicFields/FieldCases.php');
839 foreach($fields as $field){
841 if(isset($beanList[ $field['module']])){
842 $class = $beanList[ $field['module']];
843 if(!isset($field['ext4']))$field['ext4'] = '';
844 if(!isset($field['mass_update']))$field['mass_update'] = 0;
845 if(!isset($field['duplicate_merge']))$field['duplicate_merge'] = 0;
846 if(!isset($field['help']))$field['help'] = '';
848 if(file_exists($beanFiles[$class])){
849 require_once($beanFiles[$class]);
852 $fieldObject = get_widget($field['type']);
853 $fieldObject->populateFromRow($field);
854 $mod->custom_fields->use_existing_labels = true;
855 $mod->custom_fields->addFieldObject($fieldObject);
859 $GLOBALS['log']->debug('Could not install custom field ' . $field['name'] . ' for module ' . $field['module'] . ': Module does not exist');
864 function uninstall_custom_fields($fields){
865 global $beanList, $beanFiles;
866 require_once('modules/DynamicFields/DynamicField.php');
867 $dyField = new DynamicField();
869 foreach($fields as $field){
870 $class = $beanList[ $field['module']];
871 if(file_exists($beanFiles[$class])){
872 require_once($beanFiles[$class]);
874 $dyField->bean = $mod;
875 $dyField->module = $field['module'];
876 $dyField->deleteField($field['name']);
882 * ModuleInstaller->install_relationships calls install_relationship for every file included in the module package that defines a relationship, and then
883 * writes a custom/Extension/application/Ext/TableDictionary/$module.php file containing an include_once for every relationship metadata file passed to install_relationship.
884 * 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
885 * everything in 'Ext/TableDictionary/' into 'tabledictionary.ext.php'
887 function install_relationships ()
889 if (isset ( $this->installdefs [ 'relationships' ] ))
891 $this->log ( translate ( 'LBL_MI_IN_RELATIONSHIPS' ) ) ;
892 $str = "<?php \n //WARNING: The contents of this file are auto-generated\n" ;
893 $save_table_dictionary = false ;
895 if (! file_exists ( "custom/Extension/application/Ext/TableDictionary" ))
897 mkdir_recursive ( "custom/Extension/application/Ext/TableDictionary", true ) ;
900 foreach ( $this->installdefs [ 'relationships' ] as $key => $relationship )
902 $filename = basename ( $relationship [ 'meta_data' ] ) ;
903 $this->copy_path ( $relationship [ 'meta_data' ], 'custom/metadata/' . $filename ) ;
904 $this->install_relationship ( 'custom/metadata/' . $filename ) ;
905 $save_table_dictionary = true ;
907 if (! empty ( $relationship [ 'module_vardefs' ] ))
909 $relationship [ 'module_vardefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_vardefs' ] ) ;
910 $this->install_vardef ( $relationship [ 'module_vardefs' ], $relationship [ 'module' ] ) ;
913 if (! empty ( $relationship [ 'module_layoutdefs' ] ))
915 $relationship [ 'module_layoutdefs' ] = str_replace ( '<basepath>', $this->base_dir, $relationship [ 'module_layoutdefs' ] ) ;
916 $this->install_layoutdef ( $relationship [ 'module_layoutdefs' ], $relationship [ 'module' ] ) ;
919 $relName = strpos($filename, "MetaData") !== false ? substr($filename, 0, strlen($filename) - 12) : $filename;
920 $out = sugar_fopen ( "custom/Extension/application/Ext/TableDictionary/$relName.php", 'w' ) ;
921 fwrite ( $out, $str . "include('custom/metadata/$filename');\n\n?>" ) ;
927 $this->rebuild_vardefs () ;
928 $this->rebuild_layoutdefs () ;
929 if ($save_table_dictionary)
931 $this->rebuild_tabledictionary () ;
938 * Install_relationship obtains a set of relationship definitions from the filename passed in as a parameter.
939 * For each definition it calls db->createTableParams to build the relationships table if it does not exist,
940 * and SugarBean::createRelationshipMeta to add the relationship into the 'relationships' table.
942 function install_relationship($file)
944 $_REQUEST['moduleInstaller'] = true;
945 if(!file_exists($file))
947 $GLOBALS['log']->debug( 'File does not exists : '.$file);
951 $rel_dictionary = $dictionary;
952 foreach ($rel_dictionary as $rel_name => $rel_data)
954 $table = ''; // table is actually optional
955 // check if we have a table definition - not all relationships require a join table
956 if ( isset( $rel_data[ 'table' ] ) )
958 $table = $rel_data[ 'table' ];
960 if(!$this->db->tableExists($table))
962 $this->db->createTableParams($table, $rel_data[ 'fields' ], $rel_data[ 'indices' ]);
967 $GLOBALS['log']->debug("Processing relationship meta for ". $rel_name."...");
968 SugarBean::createRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
969 Relationship::delete_cache();
971 $GLOBALS['log']->debug( 'done<br>');
975 function install_layoutfields() {
976 if (!empty ( $this->installdefs [ 'layoutfields' ] ))
978 foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
980 if (!empty($fieldSet['additional_fields']))
982 $this->addFieldsToLayout($fieldSet['additional_fields']);
988 function uninstall_layoutfields() {
989 if (!empty ( $this->installdefs [ 'layoutfields' ] ))
991 foreach ( $this->installdefs [ 'layoutfields' ] as $fieldSet )
993 if (!empty($fieldSet['additional_fields']))
995 $this->removeFieldsFromLayout($fieldSet['additional_fields']);
1001 function uninstall_relationship($file, $rel_dictionary = null){
1002 if ($rel_dictionary == null)
1004 if(!file_exists($file)){
1005 $GLOBALS['log']->debug( 'File does not exists : '.$file);
1009 $rel_dictionary = $dictionary;
1012 foreach ($rel_dictionary as $rel_name => $rel_data)
1014 if (!empty($rel_data['table'])){
1015 $table = $rel_data['table'];
1018 $table = ' One-to-Many ';
1021 if ($this->db->tableExists($table) && isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1023 SugarBean::removeRelationshipMeta($rel_name, $this->db,$table,$rel_dictionary,'');
1024 $this->db->dropTableName($table);
1025 if(!$this->silent) $this->log( translate('LBL_MI_UN_RELATIONSHIPS_DROP') . $table);
1028 //Delete Layout defs
1029 // check to see if we have any vardef or layoutdef entries to remove - must have a relationship['module'] parameter if we do
1030 if (!isset($rel_data[ 'module' ]))
1032 $rel_data['relationships'][$rel_name]['lhs_module'],
1033 $rel_data['relationships'][$rel_name]['rhs_module'],
1036 $mods = array($rel_data[ 'module' ]);
1038 $filename = "$rel_name.php";
1040 foreach($mods as $mod) {
1041 if ($mod != 'application' ) {
1042 $basepath = "custom/Extension/modules/$mod/Ext/";
1044 $basepath = "custom/Extension/application/Ext/";
1047 foreach (array($filename , "custom" . $filename) as $fn) {
1048 //remove any vardefs
1049 $path = $basepath . "Vardefs/$fn" ;
1050 if (file_exists( $path ))
1051 rmdir_recursive( $path );
1053 //remove any layoutdefs
1054 $path = $basepath . "Layoutdefs/$fn" ;
1055 if( file_exists( $path ))
1057 rmdir_recursive( $path );
1062 foreach (array($filename , "custom" . $filename) as $fn) {
1063 // remove the table dictionary extension
1064 if ( file_exists("custom/Extension/application/Ext/TableDictionary/$fn"))
1065 unlink("custom/Extension/application/Ext/TableDictionary/$fn");
1067 if (file_exists("custom/metadata/{$rel_name}MetaData.php"))
1068 unlink( "custom/metadata/{$rel_name}MetaData.php" );
1073 function uninstall_relationships($include_studio_relationships = false){
1074 $relationships = array();
1076 //Find and remove studio created relationships.
1077 global $beanList, $beanFiles, $dictionary;
1078 //Load up the custom relationship definitions.
1079 if(file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')){
1080 include('custom/application/Ext/TableDictionary/tabledictionary.ext.php');
1082 //Find all the relatioships/relate fields involving this module.
1083 $rels_to_remove = array();
1084 foreach($beanList as $mod => $bean) {
1085 VardefManager::loadVardef($mod, $bean);
1086 //We can skip modules that are in this package as they will be removed anyhow
1087 if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields']))
1089 $field_defs = $dictionary[$bean]['fields'];
1090 foreach($field_defs as $field => $def)
1092 //Weed out most fields first
1093 if (isset ($def['type']))
1095 //Custom relationships created in the relationship editor
1096 if ($def['type'] == "link" && !empty($def['relationship']) && !empty($dictionary[$def['relationship']]))
1098 $rel_name = $def['relationship'];
1100 $rel_def = $dictionary[$rel_name]['relationships'][$rel_name];
1102 //Check against mods to be removed.
1103 foreach($this->modulesInPackage as $removed_mod) {
1104 if ($rel_def['lhs_module'] == $removed_mod || $rel_def['rhs_module'] == $removed_mod )
1106 $dictionary[$rel_name]['from_studio'] = true;
1107 $relationships[$rel_name] = $dictionary[$rel_name];
1111 //Custom "relate" fields created in studio also need to be removed
1112 if ($def['type'] == 'relate' && isset($def['module'])) {
1113 foreach($this->modulesInPackage as $removed_mod) {
1114 if ($def['module'] == $removed_mod)
1116 require_once 'modules/ModuleBuilder/Module/StudioModule.php' ;
1117 $studioMod = new StudioModule ( $mod );
1118 $studioMod->removeFieldFromLayouts( $field );
1119 if (isset($def['custom_module'])) {
1120 require_once ('modules/DynamicFields/DynamicField.php') ;
1121 require_once ($beanFiles [ $bean ]) ;
1122 $seed = new $bean ( ) ;
1123 $df = new DynamicField ( $mod ) ;
1124 $df->setup ( $seed ) ;
1125 //Need to load the entire field_meta_data for some field types
1126 $field_obj = $df->getFieldWidget($mod, $field);
1127 $field_obj->delete ( $df ) ;
1139 $this->uninstall_relationship(null, $relationships);
1141 if(isset($this->installdefs['relationships'])) {
1142 $relationships = $this->installdefs['relationships'];
1143 $this->log(translate('LBL_MI_UN_RELATIONSHIPS') );
1144 foreach($relationships as $relationship)
1146 // remove the metadata entry
1147 $filename = basename ( $relationship['meta_data'] );
1148 $pathname = (file_exists("custom/metadata/$filename")) ? "custom/metadata/$filename" : "metadata/$filename" ;
1149 if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1150 $this->uninstall_relationship( $pathname );
1151 if (file_exists($pathname))
1152 unlink( $pathname );
1156 if (file_exists("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php"))
1157 unlink("custom/Extension/application/Ext/TableDictionary/{$this->id_name}.php");
1158 Relationship::delete_cache();
1159 $this->rebuild_tabledictionary();
1165 function uninstall($base_dir){
1166 if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
1167 global $app_strings;
1168 $total_steps = 5; //min steps with no tasks
1170 $this->base_dir = $base_dir;
1173 'uninstall_relationships',
1175 'uninstall_dcactions',
1177 'uninstall_dashlets',
1178 'uninstall_userpage',
1179 'uninstall_administration',
1180 'uninstall_connectors',
1181 'uninstall_vardefs',
1182 'uninstall_layoutdefs',
1183 'uninstall_layoutfields',
1184 'uninstall_languages',
1185 'uninstall_logichooks',
1188 $total_steps += count($tasks); //now the real number of steps
1189 if(file_exists($this->base_dir . '/manifest.php')){
1192 display_progress_bar('install', $current_step, $total_steps);
1193 echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
1197 include($this->base_dir . '/manifest.php');
1198 $this->installdefs = $installdefs;
1199 $this->id_name = $this->installdefs['id'];
1200 $installed_modules = array();
1201 if(isset($this->installdefs['beans'])){
1203 foreach($this->installdefs['beans'] as $bean){
1205 $installed_modules[] = $bean['module'];
1206 $this->uninstall_user_prefs($bean['module']);
1208 $this->modulesInPackage = $installed_modules;
1209 $this->uninstall_beans($installed_modules);
1210 $this->uninstall_customizations($installed_modules);
1213 update_progress_bar('install', $total_steps, $total_steps);
1215 if (sugar_is_file("custom/Extension/application/Ext/Include/$this->id_name.php", 'w'))
1216 rmdir_recursive("custom/Extension/application/Ext/Include/$this->id_name.php");
1217 else if(sugar_is_file("custom/Extension/application/Ext/Include/" . DISABLED_PATH . "/$this->id_name.php", 'w'))
1218 rmdir_recursive("custom/Extension/application/Ext/Include/" . DISABLED_PATH . "/$this->id_name.php");
1220 $this->rebuild_modules();
1224 update_progress_bar('install', $current_step, $total_steps);
1228 foreach($tasks as $task){
1232 update_progress_bar('install', $current_step, $total_steps);
1235 if(isset($installdefs['custom_fields']) && (isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])){
1236 $this->log(translate('LBL_MI_UN_CUSTOMFIELD'));
1237 $this->uninstall_custom_fields($installdefs['custom_fields']);
1241 update_progress_bar('install', $current_step, $total_steps);
1244 //since we are passing $silent = true to rebuildAll() in that method it will set $this->silent = true, so
1245 //we need to save the setting to set it back after rebuildAll() completes.
1246 $silentBak = $this->silent;
1247 $this->rebuild_all(true);
1248 $this->silent = $silentBak;
1250 //#27877, If the request from MB redeploy a custom module , we will not remove the ACL actions for this package.
1251 if( !isset($_REQUEST['action']) || $_REQUEST['action']!='DeployPackage' ){
1252 $this->remove_acl_actions();
1258 update_progress_bar('install', $current_step, $total_steps);
1262 UpdateSystemTabs('Restore',$installed_modules);
1264 $this->log('<br><b>' . translate('LBL_MI_COMPLETE') . '</b>');
1266 update_progress_bar('install', $total_steps, $total_steps);
1269 die("No manifest.php Defined In $this->base_dir/manifest.php");
1273 function rebuild_languages($languages, $modules=""){
1274 foreach($languages as $language=>$value){
1275 $this->log(translate('LBL_MI_REBUILDING') . " Language...$language");
1276 $this->merge_files('Ext/Language/', $language.'.lang.ext.php', $language);
1278 foreach($modules as $module){
1279 LanguageManager::clearLanguageCache($module, $language);
1283 sugar_cache_reset();
1287 function rebuild_vardefs(){
1288 $this->log(translate('LBL_MI_REBUILDING') . " Vardefs...");
1289 $this->merge_files('Ext/Vardefs/', 'vardefs.ext.php');
1290 sugar_cache_reset();
1292 function rebuild_layoutdefs(){
1293 $this->log(translate('LBL_MI_REBUILDING') . " Layoutdefs...");
1294 $this->merge_files('Ext/Layoutdefs/', 'layoutdefs.ext.php');
1298 function rebuild_menus(){
1299 $this->log(translate('LBL_MI_REBUILDING') . " Menus...");
1300 $this->merge_files('Ext/Menus/', 'menu.ext.php');
1303 function rebuild_dashletcontainers(){
1304 $this->log(translate('LBL_MI_REBUILDING') . " DC Actions...");
1305 $this->merge_files('Ext/DashletContainer/Containers', 'dcactions.ext.php');
1308 function rebuild_modules(){
1309 $this->log(translate('LBL_MI_REBUILDING') . " Modules...");
1310 $this->merge_files('Ext/Include', 'modules.ext.php', '', true);
1313 function rebuild_administration(){
1314 $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION'));
1315 $this->merge_files('Ext/Administration/', 'administration.ext.php');
1317 function rebuild_userpage(){
1318 $this->log(translate('LBL_MI_REBUILDING') . " User Page " . translate('LBL_MI_SECTION'));
1319 $this->merge_files('Ext/UserPage/', 'userpage.ext.php');
1321 function rebuild_tabledictionary(){
1322 $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION'));
1323 $this->merge_files('Ext/TableDictionary/', 'tabledictionary.ext.php');
1326 function rebuild_relationships() {
1327 if(!$this->silent) echo translate('LBL_MI_REBUILDING') . ' Relationships';
1328 $_REQUEST['silent'] = true;
1330 include('include/modules.php');
1331 include("modules/Administration/RebuildRelationship.php");
1334 function remove_acl_actions() {
1335 global $beanFiles, $beanList, $current_user;
1336 include('include/modules.php');
1337 include("modules/ACL/remove_actions.php");
1341 * Wrapper call to modules/Administration/RepairIndex.php
1343 function repair_indices() {
1344 global $current_user,$beanFiles,$dictionary;
1345 $this->log(translate('LBL_MI_REPAIR_INDICES'));
1346 $_REQUEST['silent'] = true; // local var flagging echo'd output in repair script
1347 $_REQUEST['mode'] = 'execute'; // flag to just go ahead and run the script
1348 include("modules/Administration/RepairIndex.php");
1352 * Rebuilds the extension files found in custom/Extension
1353 * @param boolean $silent
1355 function rebuild_all($silent=false){
1356 if(defined('TEMPLATE_URL'))SugarTemplateUtilities::disableCache();
1357 $this->silent=$silent;
1358 global $sugar_config;
1360 //Check for new module extensions
1361 $this->rebuild_modules();
1363 $this->rebuild_languages($sugar_config['languages']);
1364 $this->rebuild_vardefs();
1365 $this->rebuild_layoutdefs();
1366 $this->rebuild_menus();
1367 $this->rebuild_dashletcontainers();
1368 $this->rebuild_userpage();
1369 $this->rebuild_administration();
1370 $this->rebuild_relationships();
1371 $this->rebuild_tabledictionary();
1372 //$this->repair_indices();
1373 $this->reset_opcodes();
1374 sugar_cache_reset();
1378 * 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
1379 * custom/Extension/modules/$module/<path> (_override files last) and concatenates them to custom/modules/$module/<path>/<file>.
1380 * Then it does the same thing in custom/Extension/application/<path>, concatenating those files and copying the result to custom/application/<path>/<file>
1382 function merge_files($path, $name, $filter = '', $application = false){
1384 $GLOBALS['log']->debug( get_class($this)."->merge_files() : merging module files in custom/Extension/modules/<module>/$path to custom/modules/<module>/$path$name");
1385 foreach($this->modules as $module){
1386 //$GLOBALS['log']->debug("Merging Files for: ".$module);
1387 //$GLOBALS['log']->debug("Merging Files for path: ".$path);
1388 $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1389 $extpath = "modules/$module/$path";
1390 $module_install = 'custom/Extension/'.$extpath;
1391 $shouldSave = false;
1392 if(is_dir($module_install)){
1393 $dir = dir($module_install);
1395 $override = array();
1396 while($entry = $dir->read()){
1397 if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
1398 && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
1400 if (substr($entry, 0, 9) == '_override') {
1401 $override[] = $entry;
1403 $fp = sugar_fopen($module_install . '/' . $entry, 'r');
1404 $file = fread($fp , filesize($module_install . '/' . $entry));
1405 $GLOBALS['log']->debug(get_class($this)."->merge_files(): found {$module_install}{$entry}") ;
1407 $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1411 foreach ($override as $entry) {
1412 $fp = sugar_fopen($module_install . '/' . $entry, 'r');
1413 $file = fread($fp , filesize($module_install . '/' . $entry));
1415 $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1418 $extension .= "\n?>";
1421 if(!file_exists("custom/$extpath")){
1422 mkdir_recursive("custom/$extpath", true);
1424 $out = sugar_fopen("custom/$extpath/$name", 'w');
1425 fwrite($out,$extension);
1428 if(file_exists("custom/$extpath/$name")){
1429 unlink("custom/$extpath/$name");
1436 $GLOBALS['log']->debug("Merging application files for $name in $path");
1437 //Now the application stuff
1438 $extension = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1439 $extpath = "application/$path";
1440 $module_install = 'custom/Extension/'.$extpath;
1441 $shouldSave = false;
1442 if(is_dir($module_install)){
1443 $dir = dir($module_install);
1444 while($entry = $dir->read()){
1446 if((empty($filter) || substr_count($entry, $filter) > 0) && is_file($module_install.'/'.$entry)
1447 && $entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php")
1449 $fp = sugar_fopen($module_install . '/' . $entry, 'r');
1450 $file = fread($fp , filesize($module_install . '/' . $entry));
1452 $extension .= "\n". str_replace(array('<?php', '?>', '<?PHP', '<?'), array('','', '' ,'') , $file);
1456 $extension .= "\n?>";
1458 if(!file_exists("custom/$extpath")){
1459 mkdir_recursive("custom/$extpath", true);
1461 $out = sugar_fopen("custom/$extpath/$name", 'w');
1462 fwrite($out,$extension);
1465 if(file_exists("custom/$extpath/$name")){
1466 unlink("custom/$extpath/$name");
1473 * ModuleInstaller->install_beans runs through the list of beans given, instantiates each bean, calls bean->create_tables, and then calls SugarBean::createRelationshipMeta for the
1476 function install_beans($beans){
1477 include('include/modules.php');
1478 foreach($beans as $bean){
1479 $this->log( translate('LBL_MI_IN_BEAN') . " $bean");
1480 if(isset($beanList[$bean])){
1481 $class = $beanList[$bean];
1482 if(file_exists($beanFiles[$class])){
1483 require_once($beanFiles[$class]);
1484 $mod = new $class();
1486 if(is_subclass_of($mod, 'SugarBean') && $mod->disable_vardefs == false ){
1487 $GLOBALS['log']->debug( "Creating Tables Bean : $bean");
1488 $mod->create_tables();
1489 SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir);
1492 $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
1498 function uninstall_beans($beans){
1499 include('include/modules.php');
1500 foreach($beans as $bean){
1501 $this->log( translate('LBL_MI_UN_BEAN') . " $bean");
1502 if(isset($beanList[$bean])){
1503 $class = $beanList[$bean];
1505 if(file_exists($beanFiles[$class])){
1506 require_once($beanFiles[$class]);
1507 $mod = new $class();
1509 if(is_subclass_of($mod, 'SugarBean')){
1510 $GLOBALS['log']->debug( "Drop Tables : $bean");
1511 if(isset($GLOBALS['mi_remove_tables']) && $GLOBALS['mi_remove_tables'])
1512 $mod->drop_tables();
1515 $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] );
1522 * Remove any customizations made within Studio while the module was installed.
1524 function uninstall_customizations($beans){
1525 foreach($beans as $bean){
1527 'custom/modules/' . $bean,
1528 'custom/Extension/modules/' . $bean
1530 foreach($dirs as $dir)
1533 rmdir_recursive($dir);
1540 $GLOBALS['log']->debug('ModuleInstaller:'. $str);
1546 /* BEGIN - RESTORE POINT - by MR. MILK August 31, 2005 02:15:18 PM */
1547 function copy_recursive_with_backup( $source, $dest, $backup_path, $uninstall=false ) {
1548 if(is_file($source)) {
1550 $GLOBALS['log']->debug("Restoring ... " . $source. " to " .$dest );
1551 if(copy( $source, $dest)) {
1552 if(is_writable($dest))
1553 sugar_touch( $dest, filemtime($source) );
1554 return(unlink($source));
1557 $GLOBALS['log']->debug( "Can't restore file: " . $source );
1562 if(file_exists($dest)) {
1563 $rest = clean_path($backup_path."/$dest");
1564 if( !is_dir(dirname($rest)) )
1565 mkdir_recursive(dirname($rest), true);
1567 $GLOBALS['log']->debug("Backup ... " . $dest. " to " .$rest );
1568 if(copy( $dest, $rest)) {
1569 if(is_writable($rest))
1570 sugar_touch( $rest, filemtime($dest) );
1573 $GLOBALS['log']->debug( "Can't backup file: " . $dest );
1576 return( copy( $source, $dest ) );
1579 elseif(!is_dir($source)) {
1582 return(unlink($dest));
1584 //don't do anything we already cleaned up the files using uninstall_new_files
1592 if( !is_dir($dest) && !$uninstall){
1593 sugar_mkdir( $dest );
1598 $d = dir( $source );
1599 while( $f = $d->read() ){
1600 if( $f == "." || $f == ".." ){
1603 $status &= $this->copy_recursive_with_backup( "$source/$f", "$dest/$f", $backup_path, $uninstall );
1609 private function dir_get_files($path, $base_path){
1611 if(!is_dir($path))return $files;
1613 while ($e = $d->read()){
1614 //ignore invisible files . .. ._MACOSX
1615 if(substr($e, 0, 1) == '.')continue;
1616 if(is_file($path . '/' . $e))$files[str_replace($base_path , '', $path . '/' . $e)] = str_replace($base_path , '', $path . '/' . $e);
1617 if(is_dir($path . '/' . $e))$files = array_merge($files, $this->dir_get_files($path . '/' . $e, $base_path));
1624 private function dir_file_count($path){
1625 //if its a file then it has at least 1 file in the directory
1626 if(is_file($path)) return 1;
1629 while ($e = $d->read()){
1630 //ignore invisible files . .. ._MACOSX
1631 if(substr($e, 0, 1) == '.')continue;
1632 if(is_file($path . '/' . $e))$count++;
1633 if(is_dir($path . '/' . $e))$count += $this->dir_file_count($path . '/' . $e);
1640 /* END - RESTORE POINT - by MR. MILK August 31, 2005 02:15:34 PM */
1644 * Static function which allows a module developer to abort their progress, pass in an array of errors and
1645 * redirect back to the main module loader page
1647 * @param errors an array of error messages which will be displayed on the
1648 * main module loader page once it is loaded.
1650 function abort($errors = array()){
1651 //set the errors onto the session so we can display them one the moduler loader page loads
1652 $_SESSION['MODULEINSTALLER_ERRORS'] = $errors;
1653 echo '<META HTTP-EQUIV="Refresh" content="0;url=index.php?module=Administration&action=UpgradeWizard&view=module">';
1655 //header('Location: index.php?module=Administration&action=UpgradeWizard&view=module');
1659 * Return the set of errors stored in the SESSION
1661 * @return an array of errors
1663 function getErrors(){
1664 if(!empty($_SESSION['MODULEINSTALLER_ERRORS'])){
1665 $errors = $_SESSION['MODULEINSTALLER_ERRORS'];
1666 unset($_SESSION['MODULEINSTALLER_ERRORS']);
1674 * Add any fields to the DetailView and EditView of the appropriate modules
1675 * Only add into deployed modules, as addFieldsToUndeployedLayouts has done this already for undeployed modules (and the admin might have edited the layouts already)
1676 * @param array $layoutAdditions An array of module => fieldname
1679 function addFieldsToLayout($layoutAdditions) {
1680 require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
1682 // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
1683 // In either case, we don't want to attempt to add a relate field to them
1684 // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
1685 $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
1687 foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
1689 if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
1691 foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
1693 $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
1694 $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
1695 $parser->addField ( array ( 'name' => $fieldName ) ) ;
1696 $parser->handleSave ( false ) ;
1703 function removeFieldsFromLayout($layoutAdditions) {
1704 require_once 'modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' ;
1706 // these modules either lack editviews/detailviews or use custom mechanisms for the editview/detailview.
1707 // In either case, we don't want to attempt to add a relate field to them
1708 // would be better if GridLayoutMetaDataParser could handle this gracefully, so we don't have to maintain this list here
1709 $invalidModules = array ( 'emails' , 'kbdocuments' ) ;
1711 foreach ( $layoutAdditions as $deployedModuleName => $fieldName )
1713 if ( ! in_array( strtolower ( $deployedModuleName ) , $invalidModules ) )
1715 foreach ( array ( MB_EDITVIEW , MB_DETAILVIEW ) as $view )
1717 $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . ": adding $fieldName to $view layout for module $deployedModuleName" ) ;
1718 $parser = new GridLayoutMetaDataParser ( $view, $deployedModuleName ) ;
1719 $parser->removeField ( $fieldName ) ;
1720 $parser->handleSave ( false ) ;
1728 //********** DISABLE/ENABLE FUNCTIONS
1730 function enable($base_dir, $is_upgrade = false, $previous_version = ''){
1731 global $app_strings;
1732 $this->base_dir = $base_dir;
1733 $total_steps = 3; //minimum number of steps with no tasks
1740 'enable_administration',
1742 'enable_layoutdefs',
1743 'enable_relationships',
1745 'enable_logichooks',
1748 $total_steps += count($tasks);
1749 if(file_exists($this->base_dir . '/manifest.php')){
1752 display_progress_bar('install', $current_step, $total_steps);
1753 echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
1756 require_once($this->base_dir . '/manifest.php');
1757 if($is_upgrade && !empty($previous_version)){
1758 //check if the upgrade path exists
1759 if(!empty($upgrade_manifest)){
1760 if(!empty($upgrade_manifest['upgrade_paths'])){
1761 if(!empty($upgrade_manifest['upgrade_paths'][$previous_version])){
1762 $installdefs = $upgrade_manifest['upgrade_paths'][$previous_version];
1764 $errors[] = 'No Upgrade Path Found in manifest.';
1765 $this->abort($errors);
1770 $this->id_name = $installdefs['id'];
1771 $this->installdefs = $installdefs;
1772 $installed_modules = array();
1773 if(isset($installdefs['beans'])){
1774 foreach($this->installdefs['beans'] as $bean){
1775 $installed_modules[] = $bean['module'];
1777 if(!file_exists("custom/Extension/application/Ext/Include")){
1778 mkdir_recursive("custom/Extension/application/Ext/Include", true);
1780 if (file_exists("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php'))
1781 rename("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php',"custom/Extension/application/Ext/Include/$this->id_name.php");
1782 $this->rebuild_modules();
1786 update_progress_bar('install', $current_step, $total_steps);
1789 foreach($tasks as $task){
1793 update_progress_bar('install', $current_step, $total_steps);
1799 update_progress_bar('install', $current_step, $total_steps);
1802 UpdateSystemTabs('Add',$installed_modules);
1803 $GLOBALS['log']->debug('Complete');
1806 die("No \$installdefs Defined In $this->base_dir/manifest.php");
1810 function disable($base_dir){
1811 global $app_strings;
1812 $total_steps = 3; //min steps with no tasks
1814 $this->base_dir = $base_dir;
1820 'disable_administration',
1822 'disable_layoutdefs',
1823 'disable_relationships',
1824 'disable_languages',
1825 'disable_logichooks',
1828 $total_steps += count($tasks); //now the real number of steps
1829 if(file_exists($this->base_dir . '/manifest.php')){
1832 display_progress_bar('install', $current_step, $total_steps);
1833 echo '<div id ="displayLoglink" ><a href="#" onclick="toggleDisplay(\'displayLog\')">'.$app_strings['LBL_DISPLAY_LOG'].'</a> </div><div id="displayLog" style="display:none">';
1836 require_once($this->base_dir . '/manifest.php');
1837 $this->installdefs = $installdefs;
1838 $this->id_name = $this->installdefs['id'];
1839 $installed_modules = array();
1840 if(isset($this->installdefs['beans'])){
1841 foreach($this->installdefs['beans'] as $bean){
1842 $installed_modules[] = $bean['module'];
1845 mkdir_recursive("custom/Extension/application/Ext/Include/".DISABLED_PATH, true);
1847 //Clear any older disabled version
1848 if (file_exists("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php'))
1849 rmdir_recursive("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php');
1851 if (file_exists("custom/Extension/application/Ext/Include/$this->id_name.php"))
1852 rename("custom/Extension/application/Ext/Include/$this->id_name.php", "custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php');
1853 $this->rebuild_modules();
1857 update_progress_bar('install', $current_step, $total_steps);
1859 foreach($tasks as $task){
1863 update_progress_bar('install', $current_step, $total_steps);
1868 update_progress_bar('install', $current_step, $total_steps);
1871 UpdateSystemTabs('Restore',$installed_modules);
1874 die("No manifest.php Defined In $this->base_dir/manifest.php");
1877 function enable_vardef($to_module){
1878 if(isset($this->installdefs['vardefs'])){
1879 foreach($this->installdefs['vardefs'] as $vardefs){
1880 $GLOBALS['log']->debug("Enabling Vardefs ..." .$to_module);
1881 $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs';
1882 if($to_module == 'application'){
1883 $path ='custom/Extension/' . $to_module. '/Ext/Vardefs';
1885 if(!file_exists($path)){
1886 mkdir_recursive($path, true);
1888 if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'))
1889 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
1890 if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from'])))
1891 rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from']));
1895 function enable_vardefs(){
1896 if(isset($this->installdefs['vardefs'])){
1897 foreach($this->installdefs['vardefs'] as $vardefs){
1898 $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
1899 $GLOBALS['log']->debug("Enabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']);
1900 $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs';
1901 if($vardefs['to_module'] == 'application'){
1902 $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs';
1904 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'))
1905 rename( $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
1907 if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from'])))
1908 rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from']));
1911 $this->rebuild_vardefs();
1914 function disable_vardefs(){
1915 $GLOBALS['log']->debug("Disabling Vardefs ".var_export($this->installdefs, true));
1916 if(isset($this->installdefs['vardefs'])){
1917 foreach($this->installdefs['vardefs'] as $vardefs){
1918 $vardefs['from'] = str_replace('<basepath>', $this->base_dir, $vardefs['from']);
1919 $GLOBALS['log']->debug("Disabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']);
1920 $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs';
1921 if($vardefs['to_module'] == 'application'){
1922 $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs';
1924 if(file_exists($path . '/'. $this->id_name . '.php')) {
1925 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1926 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
1928 if(file_exists($path . '/'. basename($vardefs['from'])))
1930 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1931 rename( $path . '/'. basename($vardefs['from']), $path . '/'.DISABLED_PATH.'/'.basename($vardefs['from']));
1934 $this->rebuild_vardefs();
1938 function enable_relationships(){
1939 if(isset($this->installdefs['relationships'])){
1940 $str = "<?php \n //WARNING: The contents of this file are auto-generated\n";
1941 $save_table_dictionary = false;
1942 foreach($this->installdefs['relationships'] as $relationship){
1943 $filename =basename($relationship['meta_data']);
1945 $save_table_dictionary = true;
1946 $str .= "include_once('metadata/$filename');\n";
1947 if (empty($relationship['module']))
1950 if(!empty($relationship['module_vardefs'])){
1951 $this->enable_vardef($relationship['module']);
1953 if(!empty($relationship['module_layoutdefs'])){
1954 $this->enable_layoutdef($relationship['module']);
1957 $this->rebuild_vardefs();
1958 $this->rebuild_layoutdefs();
1959 if($save_table_dictionary){
1960 if(!file_exists("custom/Extension/application/Ext/TableDictionary")){
1961 mkdir_recursive("custom/Extension/application/Ext/TableDictionary", true);
1963 if (file_exists("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php"))
1964 rename("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/$this->id_name.php");
1965 $this->rebuild_tabledictionary();
1970 function disable_relationships($action = 'disable'){
1971 if(isset($this->installdefs['relationships'])){
1972 foreach($this->installdefs['relationships'] as $relationship){
1973 $filename = basename($relationship['meta_data']);
1974 $relName = substr($filename, -12) == "MetaData.php" ? substr($filename,0,strlen($filename) - 12) : "";
1975 if (empty($relationship['module']) && empty($relName))
1978 //remove the vardefs
1979 if (empty($relName))
1980 $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Vardefs';
1981 if(!empty($relationship['module']) && $relationship['module'] == 'application'){
1982 $path ='custom/Extension/' . $relationship['module']. '/Ext/Vardefs';
1984 if(!empty($relationship['module_vardefs']) && file_exists($path . '/'. $this->id_name . '.php')){
1985 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1986 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
1988 //remove the layoutdefs
1989 if ( !empty($relationship['module']) ) {
1990 $path = 'custom/Extension/modules/' . $relationship['module']. '/Ext/Layoutdefs';
1991 if($relationship['module'] == 'application'){
1992 $path ='custom/Extension/' . $relationship['module']. '/Ext/Layoutdefs';
1996 if(!empty($relationship['module_layoutdefs']) && file_exists($path . '/'. $this->id_name . '.php')){
1997 mkdir_recursive($path . '/'.DISABLED_PATH, true);
1998 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2002 if(file_exists("custom/Extension/application/Ext/TableDictionary/$this->id_name.php")){
2003 mkdir_recursive("custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH, true);
2004 rename("custom/Extension/application/Ext/TableDictionary/$this->id_name.php", "custom/Extension/application/Ext/TableDictionary/".DISABLED_PATH."/$this->id_name.php");
2006 $this->rebuild_tabledictionary();
2007 $this->rebuild_vardefs();
2008 $this->rebuild_layoutdefs();
2012 function enable_layoutdefs(){
2013 if(isset($this->installdefs['layoutdefs'])){
2014 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
2015 $this->enable_layoutdef($layoutdefs['to_module'], $this->id_name);
2017 $this->rebuild_layoutdefs();
2020 function enable_layoutdef($to_module){
2021 $GLOBALS['log']->debug("Enabling Layout Defs ..." .$to_module);
2022 if(isset($this->installdefs['layoutdefs'])){
2023 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
2024 $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs';
2025 if($to_module == 'application'){
2026 $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs';
2028 if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'))
2030 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2032 if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from'])))
2034 rename($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']), $path . '/'. basename($layoutdefs['from']));
2040 function disable_layoutdefs(){
2041 if(isset($this->installdefs['layoutdefs'])){
2042 foreach($this->installdefs['layoutdefs'] as $layoutdefs){
2043 $layoutdefs['from'] = str_replace('<basepath>', $this->base_dir, $layoutdefs['from']);
2044 $GLOBALS['log']->debug("Disabling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']);
2045 $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
2046 if($layoutdefs['to_module'] == 'application'){
2047 $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs';
2049 if (file_exists($path . '/'. $this->id_name . '.php'))
2051 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2052 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2053 }else if (file_exists($path . '/'. basename($layoutdefs['from'])))
2055 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2056 rename( $path . '/'. basename($layoutdefs['from']), $path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']));
2059 $this->rebuild_layoutdefs();
2063 function enable_menus(){
2064 if(isset($this->installdefs['menu'])){
2065 foreach($this->installdefs['menu'] as $menu){
2066 $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
2067 $GLOBALS['log']->debug("Enabling Menu ..." . $menu['from']. " for " .$menu['to_module'] );
2068 $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
2069 if($menu['to_module'] == 'application'){
2070 $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
2073 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){
2074 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2078 $this->rebuild_menus();
2083 function disable_menus(){
2084 if(isset($this->installdefs['menu'])){
2085 foreach($this->installdefs['menu'] as $menu){
2086 $menu['from'] = str_replace('<basepath>', $this->base_dir, $menu['from']);
2087 $GLOBALS['log']->debug("Disabling Menu ..." . $menu['from']. " for " .$menu['to_module'] );
2088 $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus';
2089 if($menu['to_module'] == 'application'){
2090 $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus';
2092 if (file_exists( $path . '/'. $this->id_name . '.php'))
2094 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2095 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2098 $this->rebuild_menus();
2102 function enable_administration(){
2103 if(isset($this->installdefs['administration'])){
2104 foreach($this->installdefs['administration'] as $administration){
2105 $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
2106 $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] );
2107 $path = 'custom/Extension/modules/Administration/Ext/Administration';
2109 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){
2110 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2113 $this->rebuild_administration();
2117 function disable_administration(){
2118 if(isset($this->installdefs['administration'])){
2119 foreach($this->installdefs['administration'] as $administration){
2120 $administration['from'] = str_replace('<basepath>', $this->base_dir, $administration['from']);
2121 $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] );
2122 $path = 'custom/Extension/modules/Administration/Ext/Administration';
2123 if (file_exists($path . '/'. $this->id_name . '.php'))
2125 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2126 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2129 $this->rebuild_administration();
2133 function enable_dashlets(){
2134 if(isset($this->installdefs['dashlets'])){
2135 foreach($this->installdefs['dashlets'] as $cp){
2136 $cp['from'] = str_replace('<basepath>', $this->base_dir, $cp['from']);
2137 $path = 'custom/modules/Home/Dashlets/' . $cp['name'] . '/';
2138 $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
2139 $GLOBALS['log']->debug("Enabling Dashlet " . $cp['name'] . "..." . $cp['from'] );
2140 if (file_exists($disabled_path))
2142 rename($disabled_path, $path);
2145 include('modules/Administration/RebuildDashlets.php');
2150 function disable_dashlets(){
2151 if(isset($this->installdefs['dashlets'])){
2152 foreach($this->installdefs['dashlets'] as $cp){
2153 $path = 'custom/modules/Home/Dashlets/' . $cp['name'];
2154 $disabled_path = 'custom/modules/Home/'.DISABLED_PATH.'Dashlets/' . $cp['name'];
2155 $GLOBALS['log']->debug('Disabling ' .$path);
2156 if (file_exists($path))
2158 mkdir_recursive('custom/modules/Home/'.DISABLED_PATH.'Dashlets/', true);
2159 rename( $path, $disabled_path);
2162 include('modules/Administration/RebuildDashlets.php');
2166 function enable_languages(){
2167 $languages = array();
2168 if(isset($this->installdefs['language'])){
2169 foreach($this->installdefs['language'] as $packs){
2170 $languages[$packs['language']] = $packs['language'];
2171 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
2172 $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
2173 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
2174 if($packs['to_module'] == 'application'){
2175 $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
2178 if(!file_exists($path)){
2179 mkdir_recursive($path, true);
2181 if (file_exists($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php'))
2182 rename($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.$packs['language'].'.'. $this->id_name . '.php');
2184 $this->rebuild_languages($languages);
2188 function disable_languages(){
2189 $languages = array();
2190 if(isset($this->installdefs['language'])){
2191 foreach($this->installdefs['language'] as $packs){
2192 $languages[$packs['language']] = $packs['language'];
2193 $packs['from'] = str_replace('<basepath>', $this->base_dir, $packs['from']);
2194 $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']);
2195 $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language';
2196 if($packs['to_module'] == 'application'){
2197 $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language';
2199 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2200 if (file_exists($path.'/'.$packs['language'].'.'. $this->id_name . '.php'))
2201 rename($path.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php');
2204 $this->rebuild_languages($languages);
2208 function enable_userpage(){
2209 if(isset($this->installdefs['user_page'])){
2210 foreach($this->installdefs['user_page'] as $userpage){
2211 $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
2212 $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] );
2213 $path = 'custom/Extension/modules/Users/Ext/UserPage';
2214 if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){
2215 rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php');
2219 $this->rebuild_userpage();
2223 function disable_userpage(){
2224 if(isset($this->installdefs['user_page'])){
2225 foreach($this->installdefs['user_page'] as $userpage){
2226 $userpage['from'] = str_replace('<basepath>', $this->base_dir, $userpage['from']);
2227 $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] );
2228 $path = 'custom/Extension/modules/Users/Ext/UserPage';
2229 if (file_exists( $path . '/'. $this->id_name . '.php')) {
2230 mkdir_recursive($path . '/'.DISABLED_PATH, true);
2231 rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php');
2234 $this->rebuild_userpage();
2238 function enable_copy(){
2239 //copy files back onto file system. first perform md5 check to determine if anything has been modified
2240 //here we should just go through the files in the -restore directory and copy those back
2241 if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
2242 if(!empty($this->installdefs['copy'])){
2243 foreach($this->installdefs['copy'] as $cp){
2244 $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
2245 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] );
2247 //check if this file exists in the -restore directory
2248 if(file_exists($backup_path)){
2249 //since the file exists, then we want do an md5 of the install version and the file system version
2250 //if(is_file($backup_path) && md5_file($backup_path) == md5_file($cp['to'])){
2251 //since the files are the same then we can safely move back from the -restore
2252 //directory into the file system
2253 $GLOBALS['log']->debug("ENABLE COPY:: FROM: ".$cp['from']. " TO: ".$cp['to']);
2254 $this->copy_path($cp['from'], $cp['to']);
2256 //since they are not equal then we need to prompt the user
2264 function disable_copy(){
2265 //when we disable we want to copy the -restore files back into the file system
2266 //but we should check the version in the module install against the version on the file system
2267 //if they match then we can copy the file back, but otherwise we should ask the user.
2269 // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy()');
2270 if(isset($GLOBALS['mi_overwrite_files']) && $GLOBALS['mi_overwrite_files']){
2271 // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy():mi_overwrite_files=true');
2272 if(!empty($this->installdefs['copy'])){
2273 // $GLOBALS['log']->debug('ModuleInstaller.php->disable_copy(): installdefs not empty');
2274 foreach($this->installdefs['copy'] as $cp){
2275 $cp['to'] = clean_path(str_replace('<basepath>', $this->base_dir, $cp['to']));
2276 $backup_path = clean_path( remove_file_extension(urldecode(hashToFile($_REQUEST['install_file'])))."-restore/".$cp['to'] ); // bug 16966 tyoung - replaced missing assignment to $backup_path
2277 //check if this file exists in the -restore directory
2278 // $GLOBALS['log']->debug("ModuleInstaller.php->disable_copy(): backup_path=".$backup_path);
2279 if(file_exists($backup_path)){
2280 //since the file exists, then we want do an md5 of the install version and the file system version
2281 $from = str_replace('<basepath>', $this->base_dir, $cp['from']);
2283 //if(is_file($from) && md5_file($from) == md5_file($cp['to'])){
2284 //since the files are the same then we can safely move back from the -restore
2285 //directory into the file system
2286 $GLOBALS['log']->debug("DISABLE COPY:: FROM: ".$backup_path. " TO: ".$cp['to']);
2287 $this->copy_path($backup_path, $cp['to']);
2289 //since they are not equal then we need to prompt the user
2297 public function reset_opcodes()
2299 /* Bug 39354 - added function_exists check. Not optimal fix, but safe nonetheless.
2300 * 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,
2301 * but this file has been updated to 6.1
2303 if(function_exists('sugar_clean_opcodes')){
2304 sugar_clean_opcodes();
2310 function UpdateSystemTabs($action, $installed_modules){
2311 require_once("modules/MySettings/TabController.php");
2312 $controller = new TabController();
2313 $isSystemTabsInDB = $controller->is_system_tabs_in_db();
2314 if ($isSystemTabsInDB && !empty($installed_modules))
2320 $currentTabs = $controller->get_system_tabs();
2321 foreach ($installed_modules as $module)
2323 if(in_array($module, $currentTabs)){
2324 unset($currentTabs[$module]);
2327 $controller->set_system_tabs($currentTabs);;
2330 $currentTabs = $controller->get_system_tabs();
2331 foreach ($installed_modules as $module)
2333 if(!in_array($module, $currentTabs)){
2334 $currentTabs[$module] = $module;
2337 $controller->set_system_tabs($currentTabs);