PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/ModuleBuilder/parsers/parser.dropdown.php

https://bitbucket.org/hatim_alam/sugar-8
PHP | 343 lines | 216 code | 30 blank | 97 comment | 46 complexity | b1ece4294283a3e7d0f003e3fbcf9f08 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause, Apache-2.0, MIT, BSD-2-Clause
  1. <?php
  2. /*
  3. * Your installation or use of this SugarCRM file is subject to the applicable
  4. * terms available at
  5. * http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
  6. * If you do not agree to all of the applicable terms or do not have the
  7. * authority to bind the entity as an authorized representative, then do not
  8. * install or use this SugarCRM file.
  9. *
  10. * Copyright (C) SugarCRM Inc. All rights reserved.
  11. */
  12. use Sugarcrm\Sugarcrm\Util\Files\FileLoader;
  13. require_once 'modules/Administration/Common.php';
  14. class ParserDropDown extends ModuleBuilderParser
  15. {
  16. /**
  17. * Takes in the request params from a save request and processes
  18. * them for the save.
  19. *
  20. * @param $params $params
  21. * @param bool $finalize if false, the changes are not yet deployed.
  22. * Useful when making multiple changes in a single request. finalize() should then be called externally.
  23. */
  24. public function saveDropDown($params, $finalize = true)
  25. {
  26. global $locale;
  27. $emptyMarker = translate('LBL_BLANK');
  28. if (!empty($_REQUEST['dropdown_lang'])) {
  29. $selected_lang = $_REQUEST['dropdown_lang'];
  30. } else {
  31. $selected_lang = $locale->getAuthenticatedUserLanguage();
  32. }
  33. $type = $_REQUEST['view_package'];
  34. $dropdown_name = $params['dropdown_name'];
  35. $json = getJSONobj();
  36. $list_value = str_replace('&quot;&quot;:&quot;&quot;', '&quot;__empty__&quot;:&quot;&quot;', $params['list_value']);
  37. //Bug 21362 ENT_QUOTES- convert single quotes to escaped single quotes.
  38. $temp = $json->decode(html_entity_decode(rawurldecode($list_value), ENT_QUOTES));
  39. $dropdown = array();
  40. // dropdown is received as an array of (name,value) pairs - now extract to name=>value format preserving order
  41. // we rely here on PHP to preserve the order of the received name=>value pairs - associative arrays in PHP are ordered
  42. if (is_array($temp)) {
  43. foreach ($temp as $item) {
  44. $key = SugarCleaner::stripTags(from_html($item[0]), false);
  45. $dropdown[$key] = empty($key) ? '' : SugarCleaner::stripTags(from_html($item[1]), false);
  46. }
  47. }
  48. if (array_key_exists($emptyMarker, $dropdown)) {
  49. $output=array();
  50. foreach ($dropdown as $key => $value) {
  51. if ($emptyMarker===$key) {
  52. $output['']='';
  53. } else {
  54. $output[$key]=$value;
  55. }
  56. }
  57. $dropdown=$output;
  58. }
  59. if ($type != 'studio') {
  60. $mb = new ModuleBuilder();
  61. $module = $mb->getPackageModule($params['view_package'], $params['view_module']);
  62. $this->synchMBDropDown($dropdown_name, $dropdown, $selected_lang, $module);
  63. //Can't use synch on selected lang as we want to overwrite values, not just keys
  64. $module->mblanguage->appListStrings[$selected_lang.'.lang.php'][$dropdown_name] = $dropdown;
  65. $module->mblanguage->save($module->key_name, false, true); // tyoung - key is required parameter as of
  66. } else {
  67. $contents = return_custom_app_list_strings_file_contents($selected_lang);
  68. $my_list_strings = return_app_list_strings_language($selected_lang);
  69. if ($selected_lang == $GLOBALS['current_language']){
  70. $GLOBALS['app_list_strings'][$dropdown_name] = $dropdown;
  71. }
  72. //write to contents
  73. $contents = str_replace("?>", '', $contents);
  74. if (empty($contents)) $contents = "<?php";
  75. // Skip saveExemptDropdowns on upgrades
  76. if (empty($params['skipSaveExemptDropdowns'])) {
  77. $dropdown = $this->saveExemptDropdowns($dropdown, $dropdown_name, $my_list_strings, $selected_lang);
  78. }
  79. //add new drop down to the bottom
  80. if (!empty($params['use_push'])) {
  81. //this is for handling moduleList and such where nothing should be deleted or anything but they can be renamed
  82. $app_list_strings = array();
  83. $filePath = $this->getExtensionFilePath($dropdown_name, $selected_lang);
  84. //Include the original extension to ensure any values sourced from it are kept.
  85. if (sugar_is_file($filePath)) {
  86. include FileLoader::validateFilePath($filePath);
  87. }
  88. foreach ($dropdown as $key => $value) {
  89. //only if the value has changed or does not exist do we want to add it this way
  90. if (!isset($my_list_strings[$dropdown_name][$key])
  91. || strcmp($my_list_strings[$dropdown_name][$key], $value) != 0) {
  92. $app_list_strings[$dropdown_name][$key] = $value;
  93. }
  94. }
  95. //Now that we have all the values, save the overrides to the extension
  96. if (!empty($app_list_strings[$dropdown_name])) {
  97. $contents = "<?php\n //created: " . date('Y-m-d H:i:s') . "\n";
  98. foreach($app_list_strings[$dropdown_name] as $key => $value) {
  99. $contents .= "\n\$app_list_strings['$dropdown_name']['$key']=" . var_export_helper($value) . ";";
  100. }
  101. $this->saveContents($dropdown_name, $contents, $selected_lang);
  102. }
  103. } else {
  104. if (empty($params['skip_sync'])) {
  105. // Now synch up the keys in other languages to ensure that removed/added
  106. // Drop down values work properly under all langs.
  107. // If skip_sync, we don't want to sync ALL languages
  108. $this->synchDropDown($dropdown_name, $dropdown, $selected_lang);
  109. }
  110. $contents = $this->getExtensionContents($dropdown_name, $dropdown);
  111. $this->saveContents($dropdown_name, $contents, $selected_lang);
  112. }
  113. }
  114. //If more than one language is being updated this request, allow the caller to finalize
  115. if ($finalize) {
  116. $this->finalize($selected_lang);
  117. }
  118. }
  119. /**
  120. * Saves the dropdown as an Extension, and rebuilds the extensions for given language
  121. *
  122. * @param string $dropdownName - dropdown name, used for file name
  123. * @param string $contents - the edited dropdown contents
  124. * @param string $lang - the edited dropdown language
  125. * @return bool Success
  126. */
  127. protected function saveContents($dropdownName, $contents, $lang)
  128. {
  129. $fileName = $this->getExtensionFilePath($dropdownName, $lang);
  130. if ($fileName) {
  131. if (file_put_contents($fileName, $contents) !== false) {
  132. return true;
  133. }
  134. $GLOBALS['log']->fatal("Unable to write edited dropdown language to file: $fileName");
  135. }
  136. return false;
  137. }
  138. protected function getExtensionFilePath($dropdownName, $lang)
  139. {
  140. $dirName = 'custom/Extension/application/Ext/Language';
  141. if (SugarAutoLoader::ensureDir($dirName)) {
  142. $fileName = "$dirName/$lang.sugar_$dropdownName.php";
  143. return $fileName;
  144. } else {
  145. $GLOBALS['log']->fatal("Unable to create dir: $dirName");
  146. }
  147. return false;
  148. }
  149. /**
  150. * Clears the js cache and rebuilds the language files
  151. *
  152. * @param string $lang - language to be rebuilt, and cache cleared
  153. */
  154. public function finalize($lang)
  155. {
  156. if (!is_array($lang)) {
  157. $lang = [$lang => $lang];
  158. }
  159. SugarAutoLoader::requireWithCustom('ModuleInstall/ModuleInstaller.php');
  160. $moduleInstallerClass = SugarAutoLoader::customClass('ModuleInstaller');
  161. $mi = new $moduleInstallerClass();
  162. $mi->silent = true;
  163. $mi->rebuild_languages($lang);
  164. sugar_cache_reset();
  165. sugar_cache_reset_full();
  166. clearAllJsAndJsLangFilesWithoutOutput();
  167. // Clear out the api metadata languages cache for selected language
  168. LanguageManager::invalidateJsLanguageCache();
  169. MetaDataManager::refreshLanguagesCache($lang);
  170. }
  171. /**
  172. * function synchDropDown
  173. * Ensures that the set of dropdown keys is consistant accross all languages.
  174. *
  175. * @param string $dropdown_name The name of the dropdown to be synched
  176. * @param array $dropdown The dropdown currently being saved
  177. * @param string $selected_lang the language currently selected in Studio/MB
  178. */
  179. public function synchDropDown($dropdown_name, $dropdown, $selected_lang)
  180. {
  181. $allLanguages = get_languages();
  182. foreach ($allLanguages as $lang => $langName) {
  183. if ($lang != $selected_lang) {
  184. $listStrings = return_app_list_strings_language($lang, false);
  185. $langDropDown = array();
  186. if (isset($listStrings[$dropdown_name]) && is_array($listStrings[$dropdown_name])) {
  187. $langDropDown = $this->synchDDKeys($dropdown, $listStrings[$dropdown_name]);
  188. } else {
  189. //if the dropdown does not exist in the language, justt use what we have.
  190. $langDropDown = $dropdown;
  191. }
  192. $contents = $this->getExtensionContents($dropdown_name, $langDropDown);
  193. $this->saveContents($dropdown_name, $contents, $lang);
  194. }
  195. }
  196. }
  197. /**
  198. * function synchMBDropDown
  199. * Ensures that the set of dropdown keys is consistant accross all languages in a ModuleBuilder Module
  200. *
  201. * @param $dropdown_name The name of the dropdown to be synched
  202. * @param $dropdown array The dropdown currently being saved
  203. * @param $selected_lang String the language currently selected in Studio/MB
  204. * @param $module MBModule the module to update the languages in
  205. */
  206. public function synchMBDropDown($dropdown_name, $dropdown, $selected_lang, $module)
  207. {
  208. $selected_lang = $selected_lang . '.lang.php';
  209. foreach ($module->mblanguage->appListStrings as $lang => $listStrings) {
  210. if ($lang != $selected_lang) {
  211. $langDropDown = array();
  212. if (isset($listStrings[$dropdown_name]) && is_array($listStrings[$dropdown_name])) {
  213. $langDropDown = $this->synchDDKeys($dropdown, $listStrings[$dropdown_name]);
  214. } else {
  215. $langDropDown = $dropdown;
  216. }
  217. $module->mblanguage->appListStrings[$lang][$dropdown_name] = $langDropDown;
  218. $module->mblanguage->save($module->key_name);
  219. }
  220. }
  221. }
  222. private function synchDDKeys($dom, $sub)
  223. {
  224. //check for extra keys
  225. foreach ($sub as $key=>$value) {
  226. if (!isset($dom[$key])) {
  227. unset ($sub[$key]);
  228. }
  229. }
  230. //check for missing keys
  231. foreach ($dom as $key=>$value) {
  232. if (!isset($sub[$key])) {
  233. $sub[$key] = $value;
  234. }
  235. }
  236. return $sub;
  237. }
  238. public function getPatternMatch($dropdown_name)
  239. {
  240. // Change the regex to NOT look for GLOBALS anymore
  241. return '/\s*\$app_list_strings\s*\[\s*\''
  242. . $dropdown_name.'\'\s*\]\s*=\s*array\s*\([^\)]*\)\s*;\s*/ism';
  243. }
  244. /**
  245. * Gets the new custom dropdown list file contents after replacement
  246. *
  247. * @param string $dropdown_name
  248. * @param array $dropdown
  249. * @param string $lang
  250. * @return string
  251. */
  252. public function getNewCustomContents($dropdown_name, $dropdown, $lang)
  253. {
  254. $contents = return_custom_app_list_strings_file_contents($lang);
  255. $contents = str_replace("?>", '', $contents);
  256. if (empty($contents)) $contents = "<?php";
  257. $contents = preg_replace($this->getPatternMatch($dropdown_name), "\n\n", $contents);
  258. $contents .= "\n\n\$app_list_strings['$dropdown_name']=" . var_export_helper($dropdown) . ";";
  259. return $contents;
  260. }
  261. /**
  262. * Retrieves the contents for a language extension that includes only the dropdown modified in the contents
  263. * @param string $dropdown_name
  264. * @param array $dropdown
  265. *
  266. * @return string
  267. */
  268. protected function getExtensionContents($dropdown_name, $dropdown)
  269. {
  270. $contents = "<?php\n // created: " . date('Y-m-d H:i:s') . "\n";
  271. $contents .= "\n\$app_list_strings['$dropdown_name']=" . var_export_helper($dropdown) . ";";
  272. return $contents;
  273. }
  274. /**
  275. * Save dropdowns in which we use 'null' to remove a value
  276. *
  277. * @param $dropdown - Dropdown values
  278. * @param $dropdownName - Dropdown name
  279. * @param $myListStrings - Current app_list_strings
  280. * @param $selectedLang - Selected language
  281. *
  282. * @see getExemptDropdowns()
  283. */
  284. public function saveExemptDropdowns($dropdown, $dropdownName, $myListStrings, $selectedLang)
  285. {
  286. // Handle special dropdown item removal
  287. if (in_array($dropdownName, getExemptDropdowns())) {
  288. foreach ($myListStrings[$dropdownName] as $key => $value) {
  289. // If the value is present in the old app_list_strings but not in the new, null it
  290. if (!empty($key) && !isset($dropdown[$key])) {
  291. $dropdown[$key] = null;
  292. }
  293. }
  294. // We need to copy the NULLs if they are not set in the new dropdown
  295. // because return_app_list_strings_language() removes them from the array
  296. $files = SugarAutoLoader::existing(
  297. "custom/include/language/$selectedLang.lang.php",
  298. "custom/application/Ext/Language/$selectedLang.lang.ext.php"
  299. );
  300. foreach ($files as $customLanguage) {
  301. include FileLoader::validateFilePath($customLanguage);
  302. if (isset($app_list_strings[$dropdownName])) {
  303. foreach ($app_list_strings[$dropdownName] as $key => $value) {
  304. if ($value === null && !isset($dropdown[$key])) {
  305. $dropdown[$key] = null;
  306. }
  307. }
  308. }
  309. }
  310. }
  311. return $dropdown;
  312. }
  313. }