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 ********************************************************************************/
39 require_once('modules/Studio/DropDowns/DropDownHelper.php');
40 require_once 'modules/ModuleBuilder/parsers/parser.label.php' ;
45 * Selected language user is renaming for (eg. en_us).
49 private $selectedLanguage;
52 * An array containing the modules which should be renamed.
56 private $changedModules;
59 * An array containing the modules which have had their module strings modified as part of the
64 private $renamedModules = array();
68 * An array containing the modules and their labels to be changed when module is renamed.
70 private static $labelMap = array(
72 array('name' => 'LBL_CAMPAIGNS', 'type' => 'plural'),
73 array('name' => 'LBL_CAMPAIGN_ID', 'type' => 'singular'),
74 array('name' => 'LBL_PARENT_ACCOUNT_ID', 'type' => 'singular'),
75 array('name' => 'LBL_PROSPECT_LIST', 'type' => 'singular'),
78 array('name' => 'LBL_LIST_FORM_TITLE', 'type' => 'singular'),
79 array('name' => 'LBL_LIST_MY_BUGS', 'type' => 'plural'),
80 array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular'),
81 array('name' => 'LNK_BUG_LIST', 'type' => 'plural'),
82 array('name' => 'LNK_BUG_REPORTS', 'type' => 'singular'),
83 array('name' => 'LNK_IMPORT_BUGS', 'type' => 'plural'),
84 array('name' => 'LNK_NEW_BUG', 'type' => 'singular'),
87 array('name' => 'LBL_LIST_CONTACT', 'type' => 'singular'),
90 array('name' => 'LBL_ACCOUNTS', 'type' => 'plural'),
91 array('name' => 'LBL_CONTACTS', 'type' => 'plural'),
92 array('name' => 'LBL_LIST_CAMPAIGN_NAME', 'type' => 'singular'),
93 array('name' => 'LBL_LOG_ENTRIES_CONTACT_TITLE', 'type' => 'plural'),
94 array('name' => 'LBL_LOG_ENTRIES_LEAD_TITLE', 'type' => 'plural'),
95 array('name' => 'LBL_OPPORTUNITIES', 'type' => 'plural'),
96 array('name' => 'LBL_PROSPECT_LIST_SUBPANEL_TITLE', 'type' => 'singular'),
99 array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural'),
100 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
103 array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural'),
104 array('name' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', 'type' => 'plural'),
105 array('name' => 'LBL_CONTRACTS', 'type' => 'plural'),
106 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
107 array('name' => 'LBL_LEAD_SOURCE', 'type' => 'singular'),
108 array('name' => 'LBL_OPPORTUNITIES', 'type' => 'singular'),
109 array('name' => 'LBL_OPPORTUNITY_ROLE', 'type' => 'singular'),
110 array('name' => 'LBL_OPPORTUNITY_ROLE_ID', 'type' => 'singular'),
111 array('name' => 'LBL_PRODUCTS_TITLE', 'type' => 'plural'),
112 array('name' => 'LBL_PROSPECT_LIST', 'type' => 'singular'),
114 'Contracts' => array(
115 array('name' => 'LBL_CONTRACT_NAME', 'type' => 'singular'),
116 array('name' => 'LBL_CONTRACT_TERM', 'type' => 'singular'),
117 array('name' => 'LBL_DOCUMENTS', 'type' => 'plural'),
118 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
119 array('name' => 'LBL_LIST_CONTRACT_NAME', 'type' => 'singular'),
120 array('name' => 'LBL_OPPORTUNITY', 'type' => 'singular'),
121 array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular'),
122 array('name' => 'LBL_TOTAL_CONTRACT_VALUE', 'type' => 'singular'),
123 array('name' => 'LBL_TOTAL_CONTRACT_VALUE_USDOLLAR', 'type' => 'singular'),
124 array('name' => 'LNK_NEW_CONTRACT', 'type' => 'singular'),
126 'Documents' => array(
127 array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural'),
128 array('name' => 'LBL_CONTRACTS', 'type' => 'plural'),
129 array('name' => 'LBL_CONTRACT_NAME', 'type' => 'singular'),
130 array('name' => 'LBL_CONTRACT_STATUS', 'type' => 'singular'),
131 array('name' => 'LBL_DET_RELATED_DOCUMENT_VERSION', 'type' => 'singular'),
132 array('name' => 'LBL_DET_TEMPLATE_TYPE', 'type' => 'singular'),
133 array('name' => 'LBL_DOC_ID', 'type' => 'singular'),
134 array('name' => 'LBL_DOC_NAME', 'type' => 'singular'),
135 array('name' => 'LBL_DOC_REV_HEADER', 'type' => 'singular'),
136 array('name' => 'LBL_DOC_URL', 'type' => 'singular'),
137 array('name' => 'LBL_NAME', 'type' => 'singular'),
138 array('name' => 'LBL_TEMPLATE_TYPE', 'type' => 'singular'),
140 'KBDocuments' => array(
141 array('name' => 'LBL_CASES', 'type' => 'plural'),
142 array('name' => 'LBL_CONTRACTS', 'type' => 'plural'),
143 array('name' => 'LBL_CONTRACT_NAME', 'type' => 'plural'),
146 array('name' => 'LNK_NEW_###MODULE_SINGULAR###', 'type' => 'singular'),
147 array('name' => 'LNK_SELECT_###MODULE_PLURAL###', 'type' => 'singular'),
148 array('name' => 'LNK_SELECT_###MODULE_SINGULAR###', 'type' => 'singular'),
149 array('name' => 'LBL_ACCOUNT_DESCRIPTION', 'type' => 'singular'),
150 array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular'),
151 array('name' => 'LBL_ACCOUNT_NAME', 'type' => 'singular'),
152 array('name' => 'LBL_CAMPAIGN_ID', 'type' => 'singular'),
153 array('name' => 'LBL_CAMPAIGN_LEAD', 'type' => 'plural'),
154 array('name' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', 'type' => 'plural'),
155 array('name' => 'LBL_CONTACT_ID', 'type' => 'singular'),
156 array('name' => 'LBL_LEAD_SOURCE', 'type' => 'singular'),
157 array('name' => 'LBL_LEAD_SOURCE_DESCRIPTION', 'type' => 'singular'),
158 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
159 array('name' => 'LBL_OPPORTUNITY_AMOUNT', 'type' => 'singular'),
160 array('name' => 'LBL_OPPORTUNITY_ID', 'type' => 'singular'),
161 array('name' => 'LBL_OPPORTUNITY_NAME', 'type' => 'singular'),
164 array('name' => 'LBL_LIST_CONTACT', 'type' => 'singular'),
165 array('name' => 'LBL_LIST_JOIN_MEETING', 'type' => 'singular'),
166 array('name' => 'LBL_PASSWORD', 'type' => 'singular'),
167 array('name' => 'LBL_TYPE', 'type' => 'singular'),
168 array('name' => 'LBL_URL', 'type' => 'singular'),
171 array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular'),
172 array('name' => 'LBL_CASE_ID', 'type' => 'singular'),
173 array('name' => 'LBL_CONTACT_ID', 'type' => 'singular'),
174 array('name' => 'LBL_LIST_CONTACT', 'type' => 'singular'),
175 array('name' => 'LBL_LIST_CONTACT_NAME', 'type' => 'singular'),
176 array('name' => 'LBL_NOTE_STATUS', 'type' => 'singular'),
177 array('name' => 'LBL_OPPORTUNITY_ID', 'type' => 'singular'),
178 array('name' => 'LBL_PRODUCT_ID', 'type' => 'singular'),
179 array('name' => 'LBL_QUOTE_ID', 'type' => 'singular'),
181 'Opportunities' => array(
182 array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular'),
183 array('name' => 'LBL_AMOUNT', 'type' => 'singular'),
184 array('name' => 'LBL_CAMPAIGN_OPPORTUNITY', 'type' => 'plural'),
185 array('name' => 'LBL_CONTRACTS', 'type' => 'plural'),
186 array('name' => 'LBL_LEAD_SOURCE', 'type' => 'singular'),
187 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
188 array('name' => 'LBL_OPPORTUNITY_NAME', 'type' => 'singular'),
190 'ProductTemplates' => array(
191 array('name' => 'LBL_PRODUCT_ID', 'type' => 'singular'),
194 array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular'),
195 array('name' => 'LBL_CONTACT', 'type' => 'singular'),
196 array('name' => 'LBL_CONTACT_ID', 'type' => 'singular'),
197 array('name' => 'LBL_CONTRACTS', 'type' => 'plural'),
198 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
199 array('name' => 'LBL_LIST_NAME', 'type' => 'singular'),
200 array('name' => 'LBL_NAME', 'type' => 'singular'),
201 array('name' => 'LBL_QUOTE_ID', 'type' => 'singular'),
202 array('name' => 'LBL_RELATED_PRODUCTS', 'type' => 'plural'),
203 array('name' => 'LBL_URL', 'type' => 'singular'),
205 'ProjectTask' => array(
206 array('name' => 'LBL_PARENT_NAME', 'type' => 'singular'),
207 array('name' => 'LBL_PROJECT_ID', 'type' => 'singular'),
208 array('name' => 'LBL_PROJECT_NAME', 'type' => 'singular'),
209 array('name' => 'LBL_PROJECT_TASK_ID', 'type' => 'singular'),
212 array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural'),
213 array('name' => 'LBL_CONTACTS_RESOURCE', 'type' => 'singular'),
214 array('name' => 'LBL_LIST_FORM_TITLE', 'type' => 'singular'),
215 array('name' => 'LBL_OPPORTUNITIES', 'type' => 'plural'),
216 array('name' => 'LBL_PROJECT_HOLIDAYS_TITLE', 'type' => 'singular'),
217 array('name' => 'LBL_PROJECT_TASKS_SUBPANEL_TITLE', 'type' => 'singular'),
218 array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular'),
219 array('name' => 'LNK_NEW_PROJECT', 'type' => 'singular'),
220 array('name' => 'LNK_PROJECT_LIST', 'type' => 'singular'),
223 array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular'),
224 array('name' => 'LBL_CONTRACTS', 'type' => 'plural'),
225 array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular'),
226 array('name' => 'LBL_QUOTE_NUM', 'type' => 'singular'),
229 array('name' => 'LBL_ACCOUNT_NAME', 'type' => 'singular'),
230 array('name' => 'LBL_CAMPAIGN_ID', 'type' => 'plural'),
231 array('name' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', 'type' => 'singular'),
232 array('name' => 'LBL_PROSPECT_LIST', 'type' => 'singular'),
235 array('name' => 'LBL_CONTACT', 'type' => 'singular'),
236 array('name' => 'LBL_CONTACT_ID', 'type' => 'singular'),
237 array('name' => 'LBL_CONTACT_PHONE', 'type' => 'singular'),
244 * @param string $options
247 public function process($options = '')
249 if($options == 'SaveDropDown')
257 * Main display function.
261 protected function display()
263 global $app_list_strings, $mod_strings;
266 require_once('modules/Studio/parsers/StudioParser.php');
267 $dh = new DropDownHelper();
269 $smarty = new Sugar_Smarty();
270 $smarty->assign('MOD', $GLOBALS['mod_strings']);
271 $title=getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array("<a href='index.php?module=Administration&action=index'>".$mod_strings['LBL_MODULE_NAME']."</a>", $mod_strings['LBL_RENAME_TABS']), false);
272 $smarty->assign('title', $title);
274 $selected_lang = (!empty($_REQUEST['dropdown_lang'])?$_REQUEST['dropdown_lang']:$_SESSION['authenticated_user_language']);
275 if(empty($selected_lang))
277 $selected_lang = $GLOBALS['sugar_config']['default_language'];
280 if($selected_lang == $GLOBALS['current_language'])
282 $my_list_strings = $GLOBALS['app_list_strings'];
286 $my_list_strings = return_app_list_strings_language($selected_lang);
289 $selected_dropdown = $my_list_strings['moduleList'];
290 $selected_dropdown_singular = $my_list_strings['moduleListSingular'];
293 foreach($selected_dropdown as $key=>$value)
295 $singularValue = isset($selected_dropdown_singular[$key]) ? $selected_dropdown_singular[$key] : $value;
296 if($selected_lang != $_SESSION['authenticated_user_language'] && !empty($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$key]))
298 $selected_dropdown[$key]=array('lang'=>$value, 'user_lang'=> '['.$app_list_strings['moduleList'][$key] . ']', 'singular' => $singularValue);
302 $selected_dropdown[$key]=array('lang'=>$value, 'singular' => $singularValue);
307 $selected_dropdown = $dh->filterDropDown('moduleList', $selected_dropdown);
309 $smarty->assign('dropdown', $selected_dropdown);
310 $smarty->assign('dropdown_languages', get_languages());
313 $buttons[] = array('text'=>$mod_strings['LBL_BTN_UNDO'],'actionScript'=>"onclick='jstransaction.undo()'" );
314 $buttons[] = array('text'=>$mod_strings['LBL_BTN_REDO'],'actionScript'=>"onclick='jstransaction.redo()'" );
315 $buttons[] = array('text'=>$mod_strings['LBL_BTN_SAVE'],'actionScript'=>"onclick='if(check_form(\"editdropdown\")){document.editdropdown.submit();}'");
316 $buttonTxt = StudioParser::buildImageButtons($buttons);
317 $smarty->assign('buttons', $buttonTxt);
318 $smarty->assign('dropdown_lang', $selected_lang);
320 $editImage = SugarThemeRegistry::current()->getImage( 'edit_inline', '');
321 $smarty->assign('editImage',$editImage);
322 $deleteImage = SugarThemeRegistry::current()->getImage( 'delete_inline', '');
323 $smarty->assign('deleteImage',$deleteImage);
324 $smarty->display("modules/Studio/wizards/RenameModules.tpl");
328 * Save function responsible executing all sub-save functions required to rename a module.
332 public function save($redirect = TRUE)
334 $this->selectedLanguage = (!empty($_REQUEST['dropdown_lang'])? $_REQUEST['dropdown_lang']:$_SESSION['authenticated_user_language']);
336 //Clear all relevant language caches
337 $this->clearLanguageCaches();
339 //Retrieve changes the user is requesting and store previous values for future use.
340 $this->changedModules = $this->getChangedModules();
342 //Change module, appStrings, subpanels, and related links.
343 $this->changeAppStringEntries()->changeAllModuleModStrings()->renameAllRelatedLinks()->renameAllSubpanels()->renameAllDashlets();
345 foreach (self::$labelMap as $module=>$labelsArr) {
346 $this->renameCertainModuleModStrings($module, $labelsArr);
349 //Refresh the page again so module tabs are changed as the save process happens after module tabs are already generated.
351 SugarApplication::redirect('index.php?action=wizard&module=Studio&wizard=StudioWizard&option=RenameTabs');
355 * Rename all subpanels within the application.
358 * @return RenameModules
360 private function renameAllSubpanels()
364 foreach($beanList as $moduleName => $beanName)
366 if( class_exists($beanName) )
368 $this->renameModuleSubpanel($moduleName, $beanName, $this->changedModules);
372 $GLOBALS['log']->error("Class $beanName does not exist, unable to rename.");
381 * Rename subpanels for a particular module.
383 * @param string $moduleName The name of the module to be renamed
384 * @param string $beanName The name of the SugarBean to be renamed.
387 private function renameModuleSubpanel($moduleName, $beanName)
389 $GLOBALS['log']->info("About to rename subpanel for module: $moduleName");
390 $bean = new $beanName();
391 //Get the subpanel def
392 $subpanelDefs = $this->getSubpanelDefs($bean);
394 if( count($subpanelDefs) <= 0)
396 $GLOBALS['log']->debug("Found empty subpanel defs for $moduleName");
400 $mod_strings = return_module_language($this->selectedLanguage, $moduleName);
401 $replacementStrings = array();
403 //Iterate over all subpanel entries and see if we need to make a change.
404 foreach($subpanelDefs as $subpanelName => $subpanelMetaData)
406 $GLOBALS['log']->debug("Examining subpanel definition for potential rename: $subpanelName ");
407 //For each subpanel def, check if they are in our changed modules set.
408 foreach($this->changedModules as $changedModuleName => $renameFields)
410 if( !( isset($subpanelMetaData['type']) && $subpanelMetaData['type'] == 'collection') //Dont bother with collections
411 && $subpanelMetaData['module'] == $changedModuleName && isset($subpanelMetaData['title_key']) )
413 $replaceKey = $subpanelMetaData['title_key'];
414 if( !isset($mod_strings[$replaceKey]) )
416 $GLOBALS['log']->info("No module string entry defined for: {$mod_strings[$replaceKey]}");
419 $oldStringValue = $mod_strings[$replaceKey];
420 //At this point we don't know if we should replace the string with the plural or singular version of the new
421 //strings so we'll try both but with the plural version first since it should be longer than the singular.
422 $replacedString = str_replace($renameFields['prev_plural'], $renameFields['plural'], $oldStringValue);
423 $replacedString = str_replace($renameFields['prev_singular'], $renameFields['singular'], $replacedString);
424 $replacementStrings[$replaceKey] = $replacedString;
429 //Now we can write out the replaced language strings for each module
430 if(count($replacementStrings) > 0)
432 $GLOBALS['log']->debug("Writing out labels for subpanel changes for module $moduleName, labels: " . var_export($replacementStrings,true));
433 ParserLabel::addLabels($this->selectedLanguage, $replacementStrings, $moduleName);
434 $this->renamedModules[$moduleName] = true;
439 * Retrieve the subpanel definitions for a given SugarBean object. Unforunately we can't reuse
440 * any of the SubPanelDefinion.php functions.
442 * @param SugarBean $bean
443 * @return array The subpanel definitions.
445 private function getSubpanelDefs($bean )
448 $layout_defs = array();
450 if ( file_exists( 'modules/' . $bean->module_dir . '/metadata/subpaneldefs.php') )
451 require('modules/' . $bean->module_dir . '/metadata/subpaneldefs.php');
453 if ( file_exists( 'custom/modules/' . $bean->module_dir . '/Ext/Layoutdefs/layoutdefs.ext.php'))
454 require('custom/modules/' . $bean->module_dir . '/Ext/Layoutdefs/layoutdefs.ext.php');
456 return isset($layout_defs[$bean->module_dir]['subpanel_setup']) ? $layout_defs[$bean->module_dir]['subpanel_setup'] : $layout_defs;
460 * Rename all related linked within the application
462 * @return RenameModules
464 private function renameAllRelatedLinks()
468 foreach($beanList as $moduleName => $beanName)
470 if( class_exists($beanName) )
472 $this->renameModuleRelatedLinks($moduleName, $beanName);
476 $GLOBALS['log']->fatal("Class $beanName does not exist, unable to rename.");
484 * Rename the related links within a module.
486 * @param string $moduleName The module to be renamed
487 * @param string $moduleClass The class name of the module to be renamed
490 private function renameModuleRelatedLinks($moduleName, $moduleClass)
492 $GLOBALS['log']->info("Begining to renameModuleRelatedLinks for $moduleClass\n");
493 $tmp = new $moduleClass;
494 if( ! method_exists($tmp, 'get_related_fields') )
496 $GLOBALS['log']->info("Unable to resolve linked fields for module $moduleClass ");
500 $linkedFields = $tmp->get_related_fields();
501 $mod_strings = return_module_language($this->selectedLanguage, $moduleName);
502 $replacementStrings = array();
504 foreach($linkedFields as $link => $linkEntry)
506 //For each linked field check if the module referenced to is in our changed module list.
507 foreach($this->changedModules as $changedModuleName => $renameFields)
509 if( isset($linkEntry['module']) && $linkEntry['module'] == $changedModuleName)
511 $GLOBALS['log']->debug("Begining to rename for link field {$link}");
512 if( !isset($mod_strings[$linkEntry['vname']]) )
514 $GLOBALS['log']->debug("No label attribute for link $link, continuing.");
518 $replaceKey = $linkEntry['vname'];
519 $oldStringValue = $mod_strings[$replaceKey];
520 //At this point we don't know if we should replace the string with the plural or singular version of the new
521 //strings so we'll try both but with the plural version first since it should be longer than the singular.
522 $replacedString = str_replace($renameFields['prev_plural'], $renameFields['plural'], $oldStringValue);
523 $replacedString = str_replace($renameFields['prev_singular'], $renameFields['singular'], $replacedString);
524 $replacementStrings[$replaceKey] = $replacedString;
529 //Now we can write out the replaced language strings for each module
530 if(count($replacementStrings) > 0)
532 $GLOBALS['log']->debug("Writing out labels for link changes for module $moduleName, labels: " . var_export($replacementStrings,true));
533 ParserLabel::addLabels($this->selectedLanguage, $replacementStrings, $moduleName);
534 $this->renamedModules[$moduleName] = true;
539 * Clear all related language cache files.
543 private function clearLanguageCaches()
545 //remove the js language files
546 LanguageManager::removeJSLanguageFiles();
548 //remove lanugage cache files
549 LanguageManager::clearLanguageCache();
553 * Rename all module strings within the application for dashlets.
555 * @return RenameModules
557 private function renameAllDashlets()
559 //Load the Dashlet metadata so we know what needs to be changed
560 if(!is_file($GLOBALS['sugar_config']['cache_dir'].'dashlets/dashlets.php'))
562 require_once('include/Dashlets/DashletCacheBuilder.php');
563 $dc = new DashletCacheBuilder();
566 require_once($GLOBALS['sugar_config']['cache_dir'].'dashlets/dashlets.php');
568 foreach($this->changedModules as $moduleName => $replacementLabels)
570 $this->changeModuleDashletStrings($moduleName, $replacementLabels, $dashletsFiles);
578 * Rename the title value for all dashlets associated with a particular module
581 private function changeModuleDashletStrings($moduleName, $replacementLabels, $dashletsFiles)
583 $GLOBALS['log']->debug("Beginning to change module dashlet labels for: $moduleName ");
584 $replacementStrings = array();
586 foreach($dashletsFiles as $dashletName => $dashletData)
588 if( isset($dashletData['module']) && $dashletData['module'] == $moduleName && file_exists($dashletData['meta']) )
590 require_once( $dashletData['meta'] );
591 $dashletTitle = $dashletMeta[$dashletName]['title'];
592 $currentModuleStrings = return_module_language($this->selectedLanguage, $moduleName);
593 $modStringKey = array_search($dashletTitle,$currentModuleStrings);
594 if($modStringKey !== FALSE)
596 $replacedString = str_replace($replacementLabels['prev_plural'], $replacementLabels['plural'], $dashletTitle);
597 $replacedString = str_replace($replacementLabels['prev_singular'], $replacementLabels['singular'], $replacedString);
598 $replacementStrings[$modStringKey] = $replacedString;
603 //Now we can write out the replaced language strings for each module
604 if(count($replacementStrings) > 0)
606 $GLOBALS['log']->debug("Writing out labels for dashlet changes for module $moduleName, labels: " . var_export($replacementStrings,true));
607 ParserLabel::addLabels($this->selectedLanguage, $replacementStrings, $moduleName);
613 * Rename all module strings within the application.
615 * @return RenameModules
617 private function changeAllModuleModStrings()
619 foreach($this->changedModules as $moduleName => $replacementLabels)
621 $this->changeModuleModStrings($moduleName, $replacementLabels);
628 * Rename all module strings within the leads module.
630 * @param string $targetModule The name of the module that owns the labels to be changed.
631 * @param array $labelKeysToReplace The labels to be changed.
632 * @return RenameModules
634 private function renameCertainModuleModStrings($targetModule, $labelKeysToReplace)
636 $GLOBALS['log']->debug("Beginning to rename labels for $targetModule module");
637 foreach($this->changedModules as $moduleName => $replacementLabels)
639 $this->changeCertainModuleModStrings($moduleName, $replacementLabels, $targetModule, $labelKeysToReplace);
646 * For a particular module, rename any relevant module strings that need to be replaced.
648 * @param string $moduleName The name of the module to be renamed.
649 * @param $replacementLabels
650 * @param string $targetModule The name of the module that owns the labels to be changed.
651 * @param array $labelKeysToReplace The labels to be changed.
654 private function changeCertainModuleModStrings($moduleName, $replacementLabels, $targetModule, $labelKeysToReplace)
656 $GLOBALS['log']->debug("Beginning to change module labels for : $moduleName");
657 $currentModuleStrings = return_module_language($this->selectedLanguage, $targetModule);
659 $replacedLabels = array();
660 foreach($labelKeysToReplace as $entry)
662 $formattedLanguageKey = $this->formatModuleLanguageKey($entry['name'], $replacementLabels);
664 //If the static of dynamic key exists it should be replaced.
665 if( isset($currentModuleStrings[$formattedLanguageKey]) )
667 $oldStringValue = $currentModuleStrings[$formattedLanguageKey];
668 $newStringValue = $this->replaceSingleLabel($oldStringValue, $replacementLabels, $entry);
669 if ($oldStringValue != $newStringValue) {
670 $replacedLabels[$formattedLanguageKey] = $newStringValue;
676 ParserLabel::addLabels($this->selectedLanguage, $replacedLabels, $targetModule);
677 $this->renamedModules[$targetModule] = true;
682 * For a particular module, rename any relevant module strings that need to be replaced.
684 * @param string $moduleName The name of the module to be renamed.
685 * @param $replacementLabels
688 private function changeModuleModStrings($moduleName, $replacementLabels)
690 $GLOBALS['log']->info("Begining to change module labels for: $moduleName");
691 $currentModuleStrings = return_module_language($this->selectedLanguage, $moduleName);
692 $labelKeysToReplace = array(
693 array('name' => 'LNK_NEW_RECORD', 'type' => 'plural'), //Module built modules, Create <moduleName>
694 array('name' => 'LNK_LIST', 'type' => 'plural'), //Module built modules, View <moduleName>
695 array('name' => 'LNK_NEW_###MODULE_SINGULAR###', 'type' => 'singular'),
696 array('name' => 'LNK_###MODULE_SINGULAR###_LIST', 'type' => 'plural'),
697 array('name' => 'LNK_###MODULE_SINGULAR###_REPORTS', 'type' => 'singular'),
698 array('name' => 'LNK_IMPORT_VCARD', 'type' => 'singular'),
699 array('name' => 'LNK_IMPORT_###MODULE_PLURAL###', 'type' => 'plural'),
700 array('name' => 'LBL_LIST_FORM_TITLE', 'type' => 'singular'), //Popup title
701 array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular'), //Popup title
702 array('name' => 'LBL_HOMEPAGE_TITLE', 'type' => 'plural'),
705 $replacedLabels = array();
706 foreach($labelKeysToReplace as $entry)
708 $formattedLanguageKey = $this->formatModuleLanguageKey($entry['name'], $replacementLabels);
710 //If the static of dynamic key exists it should be replaced.
711 if( isset($currentModuleStrings[$formattedLanguageKey]) )
713 $oldStringValue = $currentModuleStrings[$formattedLanguageKey];
714 $replacedLabels[$formattedLanguageKey] = $this->replaceSingleLabel($oldStringValue, $replacementLabels, $entry);
719 ParserLabel::addLabels($this->selectedLanguage, $replacedLabels, $moduleName);
720 $this->renamedModules[$moduleName] = true;
724 * Format our dynamic keys containing module strings to a valid key depending on the module.
726 * @param string $unformatedKey
727 * @param string $replacementStrings
730 private function formatModuleLanguageKey($unformatedKey, $replacementStrings)
732 $unformatedKey = str_replace('###MODULE_SINGULAR###', strtoupper($replacementStrings['key_singular']), $unformatedKey);
733 return str_replace('###MODULE_PLURAL###', strtoupper($replacementStrings['key_plural']), $unformatedKey);
738 * Replace a label with a new value based on metadata which specifies the label as either singular or plural.
740 * @param string $oldStringValue
741 * @param string $replacementLabels
742 * @param array $replacementMetaData
745 private function replaceSingleLabel($oldStringValue, $replacementLabels, $replacementMetaData)
747 $replaceKey = 'prev_' . $replacementMetaData['type'];
748 return str_replace($replacementLabels[$replaceKey] , $replacementLabels[$replacementMetaData['type']], $oldStringValue);
753 * Save changes to the module names to the app string entries for both the moduleList and moduleListSingular entries.
755 * @return RenameModules
757 private function changeAppStringEntries()
759 $GLOBALS['log']->debug('Begining to save app string entries');
760 //Save changes to the moduleList app string entry
761 DropDownHelper::saveDropDown($_REQUEST);
763 //Save changes to the moduleListSingular app string entry
764 $newParams = array();
765 $newParams['dropdown_name'] = 'moduleListSingular';
766 $newParams['dropdown_lang'] = isset($_REQUEST['dropdown_lang']) ? $_REQUEST['dropdown_lang'] : '';
767 $newParams['use_push'] = true;
768 DropDownHelper::saveDropDown($this->createModuleListSingularPackage($newParams, $this->changedModules));
773 * Create an array entry that can be passed to the DropDownHelper:saveDropDown function so we can re-utilize
776 * @param array $params
777 * @param array $changedModules
780 private function createModuleListSingularPackage($params, $changedModules)
783 foreach($changedModules as $moduleName => $package)
785 $singularString = $package['singular'];
787 $params['slot_' . $count] = $count;
788 $params['key_' . $count] = $moduleName;
789 $params['value_' . $count] = $singularString;
790 $params['delete_' . $count] = '';
800 * Determine which modules have been updated and return an array with the module name as the key
801 * and the singular/plural entries as the value.
805 private function getChangedModules()
808 $allModuleEntries = array();
812 $selected_lang = (!empty($params['dropdown_lang'])?$params['dropdown_lang']:$_SESSION['authenticated_user_language']);
813 $current_app_list_string = return_app_list_strings_language($selected_lang);
815 while(isset($params['slot_' . $count]))
817 $index = $params['slot_' . $count];
818 $key = (isset($params['key_' . $index]))?remove_xss(from_html($params['key_' . $index])): 'BLANK';
819 $value = (isset($params['value_' . $index]))?remove_xss(from_html($params['value_' . $index])): '';
820 $svalue = (isset($params['svalue_' . $index]))?remove_xss(from_html($params['svalue_' . $index])): $value;
825 $value = trim($value);
826 $svalue = trim($svalue);
828 //If the module key dne then do not continue with this rename.
829 if( isset($current_app_list_string['moduleList'][$key]) )
830 $allModuleEntries[$key] = array('s' => $svalue, 'p' => $value);
832 $_REQUEST['delete_' . $count] = TRUE;
839 foreach($allModuleEntries as $k => $e)
843 $prev_plural = $current_app_list_string['moduleList'][$k];
844 $prev_singular = isset($current_app_list_string['moduleListSingular'][$k]) ? $current_app_list_string['moduleListSingular'][$k] : $prev_plural;
845 if( strcmp($prev_plural, $pvalue) != 0 || (strcmp($prev_singular, $svalue) != 0) )
847 $results[$k] = array('singular' => $svalue, 'plural' => $pvalue, 'prev_singular' => $prev_singular, 'prev_plural' => $prev_plural,
848 'key_plural' => $k, 'key_singular' => $this->getModuleSingularKey($k)
859 * Return the 'singular' name of a module (Eg. Opportunity for Opportunities) given a moduleName which is a key
860 * in the app string moduleList array. If no entry is found, simply return the moduleName as this is consistant with modules
861 * built by moduleBuilder.
863 * @param string $moduleName
864 * @return string The 'singular' name of a module.
866 private function getModuleSingularKey($moduleName)
868 $className = isset($GLOBALS['beanList'][$moduleName]) ? $GLOBALS['beanList'][$moduleName] : null;
869 if( is_null($className) || ! class_exists($className) )
871 $GLOBALS['log']->error("Unable to get module singular key for class: $className");
875 $tmp = new $className();
876 if( property_exists($tmp, 'object_name') )
877 return $tmp->object_name;
883 * Return an array of the modules whos mod_strings have been modified.
887 public function getRenamedModules()
889 return $this->renamedModules;