PageRenderTime 62ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/include/MVC/View/SugarView.php

https://bitbucket.org/cviolette/sugarcrm
PHP | 1626 lines | 1086 code | 211 blank | 329 comment | 236 complexity | ed5c6cb004cb28478d409b806f6bd6ce MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause

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

  1. <?php
  2. /*********************************************************************************
  3. * SugarCRM Community Edition is a customer relationship management program developed by
  4. * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License version 3 as published by the
  8. * Free Software Foundation with the addition of the following permission added
  9. * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  10. * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  11. * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  12. *
  13. * This program is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  15. * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License along with
  19. * this program; if not, see http://www.gnu.org/licenses or write to the Free
  20. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21. * 02110-1301 USA.
  22. *
  23. * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  24. * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  25. *
  26. * The interactive user interfaces in modified source and object code versions
  27. * of this program must display Appropriate Legal Notices, as required under
  28. * Section 5 of the GNU Affero General Public License version 3.
  29. *
  30. * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
  31. * these Appropriate Legal Notices must retain the display of the "Powered by
  32. * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  33. * technical reasons, the Appropriate Legal Notices must display the words
  34. * "Powered by SugarCRM".
  35. ********************************************************************************/
  36. /**
  37. * Base Sugar view
  38. * @api
  39. */
  40. class SugarView
  41. {
  42. /**
  43. * This array is meant to hold an objects/data that we would like to pass between
  44. * the controller and the view. The bean will automatically be set for us, but this
  45. * is meant to hold anything else.
  46. */
  47. var $view_object_map = array();
  48. /**
  49. * The name of the current module.
  50. */
  51. var $module = '';
  52. /**
  53. * The name of the current action.
  54. */
  55. var $action = '';
  56. /**
  57. */
  58. var $bean = null;
  59. /**
  60. * Sugar_Smarty. This is useful if you have a view and a subview you can
  61. * share the same smarty object.
  62. */
  63. var $ss = null;
  64. /**
  65. * Any errors that occured this can either be set by the view or the controller or the model
  66. */
  67. var $errors = array();
  68. /**
  69. * Set to true if you do not want to display errors from SugarView::displayErrors(); instead they will be returned
  70. */
  71. var $suppressDisplayErrors = false;
  72. /**
  73. * Options for what UI elements to hide/show/
  74. */
  75. var $options = array('show_header' => true, 'show_title' => true, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => true, 'show_javascript' => true, 'view_print' => false,);
  76. var $type = null;
  77. var $responseTime;
  78. var $fileResources;
  79. /**
  80. * Constructor which will peform the setup.
  81. */
  82. public function SugarView(
  83. $bean = null,
  84. $view_object_map = array()
  85. )
  86. {
  87. }
  88. public function init(
  89. $bean = null,
  90. $view_object_map = array()
  91. )
  92. {
  93. $this->bean = $bean;
  94. $this->view_object_map = $view_object_map;
  95. $this->action = $GLOBALS['action'];
  96. $this->module = $GLOBALS['module'];
  97. $this->_initSmarty();
  98. }
  99. protected function _initSmarty()
  100. {
  101. $this->ss = new Sugar_Smarty();
  102. $this->ss->assign('MOD', $GLOBALS['mod_strings']);
  103. $this->ss->assign('APP', $GLOBALS['app_strings']);
  104. }
  105. /**
  106. * This method will be called from the controller and is not meant to be overridden.
  107. */
  108. public function process()
  109. {
  110. LogicHook::initialize();
  111. $this->_checkModule();
  112. //trackView has to be here in order to track for breadcrumbs
  113. $this->_trackView();
  114. //For the ajaxUI, we need to use output buffering to return the page in an ajax friendly format
  115. if ($this->_getOption('json_output')){
  116. ob_start();
  117. if(!empty($_REQUEST['ajax_load']) && !empty($_REQUEST['loadLanguageJS'])) {
  118. echo $this->_getModLanguageJS();
  119. }
  120. }
  121. if ($this->_getOption('show_header')) {
  122. $this->displayHeader();
  123. } else {
  124. $this->renderJavascript();
  125. }
  126. $this->_buildModuleList();
  127. $this->preDisplay();
  128. $this->displayErrors();
  129. $this->display();
  130. if ( !empty($this->module) ) {
  131. $GLOBALS['logic_hook']->call_custom_logic($this->module, 'after_ui_frame');
  132. } else {
  133. $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_frame');
  134. }
  135. if ($this->_getOption('show_subpanels') && !empty($_REQUEST['record'])) $this->_displaySubPanels();
  136. if ($this->action === 'Login') {
  137. //this is needed for a faster loading login page ie won't render unless the tables are closed
  138. ob_flush();
  139. }
  140. if ($this->_getOption('show_footer')) $this->displayFooter();
  141. $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_footer');
  142. if ($this->_getOption('json_output'))
  143. {
  144. $content = ob_get_clean();
  145. $module = $this->module;
  146. $ajax_ret = array(
  147. 'content' => mb_detect_encoding($content) == "UTF-8" ? $content : utf8_encode($content),
  148. 'menu' => array(
  149. 'module' => $module,
  150. 'label' => translate($module),
  151. $this->getMenu($module),
  152. ),
  153. 'title' => $this->getBrowserTitle(),
  154. 'action' => isset($_REQUEST['action']) ? $_REQUEST['action'] : "",
  155. 'record' => isset($_REQUEST['record']) ? $_REQUEST['record'] : "",
  156. 'favicon' => $this->getFavicon(),
  157. );
  158. if(SugarThemeRegistry::current()->name == 'Classic')
  159. $ajax_ret['moduleList'] = $this->displayHeader(true);
  160. if(empty($this->responseTime))
  161. $this->_calculateFooterMetrics();
  162. $ajax_ret['responseTime'] = $this->responseTime;
  163. $json = getJSONobj();
  164. echo $json->encode($ajax_ret);
  165. $GLOBALS['app']->headerDisplayed = false;
  166. ob_flush();
  167. }
  168. //Do not track if there is no module or if module is not a String
  169. $this->_track();
  170. }
  171. /**
  172. * This method will display the errors on the page.
  173. */
  174. public function displayErrors()
  175. {
  176. $errors = '';
  177. foreach($this->errors as $error) {
  178. $errors .= '<span class="error">' . $error . '</span><br>';
  179. }
  180. if ( !$this->suppressDisplayErrors ) {
  181. echo $errors;
  182. }
  183. else {
  184. return $errors;
  185. }
  186. }
  187. /**
  188. * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
  189. * to allow a view to do some preprocessing before the display method is called. This becomes
  190. * useful when you have a view defined at the application level and then within a module
  191. * have a sub-view that extends from this application level view. The application level
  192. * view can do the setup in preDisplay() that is common to itself and any subviews
  193. * and then the subview can just override display(). If it so desires, can also override
  194. * preDisplay().
  195. */
  196. public function preDisplay()
  197. {
  198. }
  199. /**
  200. * [OVERRIDE] - This method is meant to overidden in a subclass. This method
  201. * will handle the actual display logic of the view.
  202. */
  203. public function display()
  204. {
  205. }
  206. /**
  207. * trackView
  208. */
  209. protected function _trackView()
  210. {
  211. $action = strtolower($this->action);
  212. //Skip save, tracked in SugarBean instead
  213. if($action == 'save') {
  214. return;
  215. }
  216. $trackerManager = TrackerManager::getInstance();
  217. $timeStamp = TimeDate::getInstance()->nowDb();
  218. if($monitor = $trackerManager->getMonitor('tracker')){
  219. $monitor->setValue('action', $action);
  220. $monitor->setValue('user_id', $GLOBALS['current_user']->id);
  221. $monitor->setValue('module_name', $this->module);
  222. $monitor->setValue('date_modified', $timeStamp);
  223. $monitor->setValue('visible', (($monitor->action == 'detailview') || ($monitor->action == 'editview')
  224. ) ? 1 : 0);
  225. if (!empty($this->bean->id)) {
  226. $monitor->setValue('item_id', $this->bean->id);
  227. $monitor->setValue('item_summary', $this->bean->get_summary_text());
  228. }
  229. //If visible is true, but there is no bean, do not track (invalid/unauthorized reference)
  230. //Also, do not track save actions where there is no bean id
  231. if($monitor->visible && empty($this->bean->id)) {
  232. $trackerManager->unsetMonitor($monitor);
  233. return;
  234. }
  235. $trackerManager->saveMonitor($monitor, true, true);
  236. }
  237. }
  238. /**
  239. * Displays the header on section of the page; basically everything before the content
  240. */
  241. public function displayHeader($retModTabs=false)
  242. {
  243. global $theme;
  244. global $max_tabs;
  245. global $app_strings;
  246. global $current_user;
  247. global $sugar_config;
  248. global $app_list_strings;
  249. global $mod_strings;
  250. global $current_language;
  251. $GLOBALS['app']->headerDisplayed = true;
  252. $themeObject = SugarThemeRegistry::current();
  253. $theme = $themeObject->__toString();
  254. $ss = new Sugar_Smarty();
  255. $ss->assign("APP", $app_strings);
  256. $ss->assign("THEME", $theme);
  257. $ss->assign("THEME_IE6COMPAT", $themeObject->ie6compat ? 'true':'false');
  258. $ss->assign("MODULE_NAME", $this->module);
  259. $ss->assign("langHeader", get_language_header());
  260. // set ab testing if exists
  261. $testing = (isset($_REQUEST["testing"]) ? $_REQUEST['testing'] : "a");
  262. $ss->assign("ABTESTING", $testing);
  263. // get browser title
  264. $ss->assign("SYSTEM_NAME", $this->getBrowserTitle());
  265. // get css
  266. $css = $themeObject->getCSS();
  267. if ($this->_getOption('view_print')) {
  268. $css .= '<link rel="stylesheet" type="text/css" href="'.$themeObject->getCSSURL('print.css').'" media="all" />';
  269. }
  270. $ss->assign("SUGAR_CSS",$css);
  271. // get javascript
  272. ob_start();
  273. $this->renderJavascript();
  274. $ss->assign("SUGAR_JS",ob_get_contents().$themeObject->getJS());
  275. ob_end_clean();
  276. // get favicon
  277. if(isset($GLOBALS['sugar_config']['default_module_favicon']))
  278. $module_favicon = $GLOBALS['sugar_config']['default_module_favicon'];
  279. else
  280. $module_favicon = false;
  281. $favicon = $this->getFavicon();
  282. $ss->assign('FAVICON_URL', $favicon['url']);
  283. // build the shortcut menu
  284. $shortcut_menu = array();
  285. foreach ( $this->getMenu() as $key => $menu_item )
  286. $shortcut_menu[$key] = array(
  287. "URL" => $menu_item[0],
  288. "LABEL" => $menu_item[1],
  289. "MODULE_NAME" => $menu_item[2],
  290. "IMAGE" => $themeObject
  291. ->getImage($menu_item[2],"border='0' align='absmiddle'",null,null,'.gif',$menu_item[1]),
  292. );
  293. $ss->assign("SHORTCUT_MENU",$shortcut_menu);
  294. // handle rtl text direction
  295. if(isset($_REQUEST['RTL']) && $_REQUEST['RTL'] == 'RTL'){
  296. $_SESSION['RTL'] = true;
  297. }
  298. if(isset($_REQUEST['LTR']) && $_REQUEST['LTR'] == 'LTR'){
  299. unset($_SESSION['RTL']);
  300. }
  301. if(isset($_SESSION['RTL']) && $_SESSION['RTL']){
  302. $ss->assign("DIR", 'dir="RTL"');
  303. }
  304. // handle resizing of the company logo correctly on the fly
  305. $companyLogoURL = $themeObject->getImageURL('company_logo.png');
  306. $companyLogoURL_arr = explode('?', $companyLogoURL);
  307. $companyLogoURL = $companyLogoURL_arr[0];
  308. $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes');
  309. if(!empty($company_logo_attributes)) {
  310. $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]);
  311. $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]);
  312. $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]);
  313. }
  314. else {
  315. // Always need to md5 the file
  316. $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL));
  317. list($width,$height) = getimagesize($companyLogoURL);
  318. if ( $width > 212 || $height > 40 ) {
  319. $resizePctWidth = ($width - 212)/212;
  320. $resizePctHeight = ($height - 40)/40;
  321. if ( $resizePctWidth > $resizePctHeight )
  322. $resizeAmount = $width / 212;
  323. else
  324. $resizeAmount = $height / 40;
  325. $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount)));
  326. $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount)));
  327. }
  328. else {
  329. $ss->assign("COMPANY_LOGO_WIDTH", $width);
  330. $ss->assign("COMPANY_LOGO_HEIGHT", $height);
  331. }
  332. // Let's cache the results
  333. sugar_cache_put('company_logo_attributes',
  334. array(
  335. $ss->get_template_vars("COMPANY_LOGO_MD5"),
  336. $ss->get_template_vars("COMPANY_LOGO_WIDTH"),
  337. $ss->get_template_vars("COMPANY_LOGO_HEIGHT")
  338. )
  339. );
  340. }
  341. $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5"));
  342. // get the global links
  343. $gcls = array();
  344. $global_control_links = array();
  345. require("include/globalControlLinks.php");
  346. foreach($global_control_links as $key => $value) {
  347. if ($key == 'users') { //represents logout link.
  348. $ss->assign("LOGOUT_LINK", $value['linkinfo'][key($value['linkinfo'])]);
  349. $ss->assign("LOGOUT_LABEL", key($value['linkinfo']));//key value for first element.
  350. continue;
  351. }
  352. foreach ($value as $linkattribute => $attributevalue) {
  353. // get the main link info
  354. if ( $linkattribute == 'linkinfo' ) {
  355. $gcls[$key] = array(
  356. "LABEL" => key($attributevalue),
  357. "URL" => current($attributevalue),
  358. "SUBMENU" => array(),
  359. );
  360. if(substr($gcls[$key]["URL"], 0, 11) == "javascript:") {
  361. $gcls[$key]["ONCLICK"] = substr($gcls[$key]["URL"],11);
  362. $gcls[$key]["URL"] = "javascript:void(0)";
  363. }
  364. }
  365. // and now the sublinks
  366. if ( $linkattribute == 'submenu' && is_array($attributevalue) ) {
  367. foreach ($attributevalue as $submenulinkkey => $submenulinkinfo)
  368. $gcls[$key]['SUBMENU'][$submenulinkkey] = array(
  369. "LABEL" => key($submenulinkinfo),
  370. "URL" => current($submenulinkinfo),
  371. );
  372. if(substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"], 0, 11) == "javascript:") {
  373. $gcls[$key]['SUBMENU'][$submenulinkkey]["ONCLICK"] = substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"],11);
  374. $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "javascript:void(0)";
  375. }
  376. }
  377. }
  378. }
  379. $ss->assign("GCLS",$gcls);
  380. $ss->assign("SEARCH", isset($_REQUEST['query_string']) ? $_REQUEST['query_string'] : '');
  381. if ($this->action == "EditView" || $this->action == "Login")
  382. $ss->assign("ONLOAD", 'onload="set_focus()"');
  383. $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
  384. // get other things needed for page style popup
  385. if (isset($_SESSION["authenticated_user_id"])) {
  386. // get the current user name and id
  387. $ss->assign("CURRENT_USER", $current_user->full_name == '' || !showFullName()
  388. ? $current_user->user_name : $current_user->full_name );
  389. $ss->assign("CURRENT_USER_ID", $current_user->id);
  390. // get the last viewed records
  391. $tracker = new Tracker();
  392. $history = $tracker->get_recently_viewed($current_user->id);
  393. foreach ( $history as $key => $row ) {
  394. $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']);
  395. $history[$key]['image'] = SugarThemeRegistry::current()
  396. ->getImage($row['module_name'],'border="0" align="absmiddle"',null,null,'.gif',$row['item_summary']);
  397. }
  398. $ss->assign("recentRecords",$history);
  399. }
  400. $bakModStrings = $mod_strings;
  401. if (isset($_SESSION["authenticated_user_id"]) ) {
  402. // get the module list
  403. $moduleTopMenu = array();
  404. $max_tabs = $current_user->getPreference('max_tabs');
  405. // Attempt to correct if max tabs count is extremely high.
  406. if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10 ) {
  407. $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
  408. $current_user->setPreference('max_tabs', $max_tabs, 0, 'global');
  409. }
  410. $moduleTab = $this->_getModuleTab();
  411. $ss->assign('MODULE_TAB',$moduleTab);
  412. // See if they are using grouped tabs or not (removed in 6.0, returned in 6.1)
  413. $user_navigation_paradigm = $current_user->getPreference('navigation_paradigm');
  414. if ( !isset($user_navigation_paradigm) ) {
  415. $user_navigation_paradigm = $GLOBALS['sugar_config']['default_navigation_paradigm'];
  416. }
  417. // Get the full module list for later use
  418. foreach ( query_module_access_list($current_user) as $module ) {
  419. // Bug 25948 - Check for the module being in the moduleList
  420. if ( isset($app_list_strings['moduleList'][$module]) ) {
  421. $fullModuleList[$module] = $app_list_strings['moduleList'][$module];
  422. }
  423. }
  424. if(!should_hide_iframes()) {
  425. $iFrame = new iFrame();
  426. $frames = $iFrame->lookup_frames('tab');
  427. foreach($frames as $key => $values){
  428. $fullModuleList[$key] = $values;
  429. }
  430. }
  431. elseif (isset($fullModuleList['iFrames'])) {
  432. unset($fullModuleList['iFrames']);
  433. }
  434. if ( $user_navigation_paradigm == 'gm' && isset($themeObject->group_tabs) && $themeObject->group_tabs) {
  435. // We are using grouped tabs
  436. require_once('include/GroupedTabs/GroupedTabStructure.php');
  437. $groupedTabsClass = new GroupedTabStructure();
  438. $modules = query_module_access_list($current_user);
  439. //handle with submoremodules
  440. $max_tabs = $current_user->getPreference('max_tabs');
  441. // If the max_tabs isn't set incorrectly, set it within the range, to the default max sub tabs size
  442. if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10){
  443. // We have a default value. Use it
  444. if(isset($GLOBALS['sugar_config']['default_max_tabs'])){
  445. $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
  446. }
  447. else{
  448. $max_tabs = 8;
  449. }
  450. }
  451. $subMoreModules = false;
  452. $groupTabs = $groupedTabsClass->get_tab_structure(get_val_array($modules));
  453. // We need to put this here, so the "All" group is valid for the user's preference.
  454. $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
  455. // Setup the default group tab.
  456. $allGroup = $app_strings['LBL_TABGROUP_ALL'];
  457. $ss->assign('currentGroupTab',$allGroup);
  458. $currentGroupTab = $allGroup;
  459. $usersGroup = $current_user->getPreference('theme_current_group');
  460. // Figure out which tab they currently have selected (stored as a user preference)
  461. if ( !empty($usersGroup) && isset($groupTabs[$usersGroup]) ) {
  462. $currentGroupTab = $usersGroup;
  463. } else {
  464. $current_user->setPreference('theme_current_group',$currentGroupTab);
  465. }
  466. $ss->assign('currentGroupTab',$currentGroupTab);
  467. $usingGroupTabs = true;
  468. } else {
  469. // Setup the default group tab.
  470. $ss->assign('currentGroupTab',$app_strings['LBL_TABGROUP_ALL']);
  471. $usingGroupTabs = false;
  472. $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
  473. }
  474. $topTabList = array();
  475. // Now time to go through each of the tab sets and fix them up.
  476. foreach ( $groupTabs as $tabIdx => $tabData ) {
  477. $topTabs = $tabData['modules'];
  478. if ( ! is_array($topTabs) ) {
  479. $topTabs = array();
  480. }
  481. $extraTabs = array();
  482. // Split it in to the tabs that go across the top, and the ones that are on the extra menu.
  483. if ( count($topTabs) > $max_tabs ) {
  484. $extraTabs = array_splice($topTabs,$max_tabs);
  485. }
  486. // Make sure the current module is accessable through one of the top tabs
  487. if ( !isset($topTabs[$moduleTab]) ) {
  488. // Nope, we need to add it.
  489. // First, take it out of the extra menu, if it's there
  490. if ( isset($extraTabs[$moduleTab]) ) {
  491. unset($extraTabs[$moduleTab]);
  492. }
  493. if ( count($topTabs) >= $max_tabs - 1 ) {
  494. // We already have the maximum number of tabs, so we need to shuffle the last one
  495. // from the top to the first one of the extras
  496. $lastElem = array_splice($topTabs,$max_tabs-1);
  497. $extraTabs = $lastElem + $extraTabs;
  498. }
  499. if ( !empty($moduleTab) ) {
  500. $topTabs[$moduleTab] = $app_list_strings['moduleList'][$moduleTab];
  501. }
  502. }
  503. /*
  504. // This was removed, but I like the idea, so I left the code in here in case we decide to turn it back on
  505. // If we are using group tabs, add all the "hidden" tabs to the end of the extra menu
  506. if ( $usingGroupTabs ) {
  507. foreach($fullModuleList as $moduleKey => $module ) {
  508. if ( !isset($topTabs[$moduleKey]) && !isset($extraTabs[$moduleKey]) ) {
  509. $extraTabs[$moduleKey] = $module;
  510. }
  511. }
  512. }
  513. */
  514. // Get a unique list of the top tabs so we can build the popup menus for them
  515. foreach ( $topTabs as $moduleKey => $module ) {
  516. $topTabList[$moduleKey] = $module;
  517. }
  518. $groupTabs[$tabIdx]['modules'] = $topTabs;
  519. $groupTabs[$tabIdx]['extra'] = $extraTabs;
  520. }
  521. }
  522. if ( isset($topTabList) && is_array($topTabList) ) {
  523. // Adding shortcuts array to menu array for displaying shortcuts associated with each module
  524. $shortcutTopMenu = array();
  525. foreach($topTabList as $module_key => $label) {
  526. global $mod_strings;
  527. $mod_strings = return_module_language($current_language, $module_key);
  528. foreach ( $this->getMenu($module_key) as $key => $menu_item ) {
  529. $shortcutTopMenu[$module_key][$key] = array(
  530. "URL" => $menu_item[0],
  531. "LABEL" => $menu_item[1],
  532. "MODULE_NAME" => $menu_item[2],
  533. "IMAGE" => $themeObject
  534. ->getImage($menu_item[2],"border='0' align='absmiddle'",null,null,'.gif',$menu_item[1]),
  535. "ID" => $menu_item[2]."_link",
  536. );
  537. }
  538. }
  539. $ss->assign("groupTabs",$groupTabs);
  540. $ss->assign("shortcutTopMenu",$shortcutTopMenu);
  541. $ss->assign('USE_GROUP_TABS',$usingGroupTabs);
  542. // This is here for backwards compatibility, someday, somewhere, it will be able to be removed
  543. $ss->assign("moduleTopMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules']);
  544. $ss->assign("moduleExtraMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['extra']);
  545. }
  546. if ( isset($extraTabs) && is_array($extraTabs) ) {
  547. // Adding shortcuts array to extra menu array for displaying shortcuts associated with each module
  548. $shortcutExtraMenu = array();
  549. foreach($extraTabs as $module_key => $label) {
  550. global $mod_strings;
  551. $mod_strings = return_module_language($current_language, $module_key);
  552. foreach ( $this->getMenu($module_key) as $key => $menu_item ) {
  553. $shortcutExtraMenu[$module_key][$key] = array(
  554. "URL" => $menu_item[0],
  555. "LABEL" => $menu_item[1],
  556. "MODULE_NAME" => $menu_item[2],
  557. "IMAGE" => $themeObject
  558. ->getImage($menu_item[2],"border='0' align='absmiddle'",null,null,'.gif',$menu_item[1]),
  559. "ID" => $menu_item[2]."_link",
  560. );
  561. }
  562. }
  563. $ss->assign("shortcutExtraMenu",$shortcutExtraMenu);
  564. }
  565. if(!empty($current_user)){
  566. $ss->assign("max_tabs", $current_user->getPreference("max_tabs"));
  567. }
  568. $imageURL = SugarThemeRegistry::current()->getImageURL("dashboard.png");
  569. $homeImage = "<img src='$imageURL'>";
  570. $ss->assign("homeImage",$homeImage);
  571. global $mod_strings;
  572. $mod_strings = $bakModStrings;
  573. $headerTpl = $themeObject->getTemplate('header.tpl');
  574. if (inDeveloperMode() )
  575. $ss->clear_compiled_tpl($headerTpl);
  576. if ($retModTabs)
  577. {
  578. return $ss->fetch($themeObject->getTemplate('_headerModuleList.tpl'));
  579. } else {
  580. $ss->display($headerTpl);
  581. $this->includeClassicFile('modules/Administration/DisplayWarnings.php');
  582. $errorMessages = SugarApplication::getErrorMessages();
  583. if ( !empty($errorMessages)) {
  584. foreach ( $errorMessages as $error_message ) {
  585. echo('<p class="error">' . $error_message.'</p>');
  586. }
  587. }
  588. }
  589. }
  590. function getModuleMenuHTML()
  591. {
  592. }
  593. /**
  594. * If the view is classic then this method will include the file and
  595. * setup any global variables.
  596. *
  597. * @param string $file
  598. */
  599. public function includeClassicFile(
  600. $file
  601. )
  602. {
  603. global $sugar_config, $theme, $current_user, $sugar_version, $sugar_flavor, $mod_strings, $app_strings, $app_list_strings, $action;
  604. global $gridline, $request_string, $modListHeader, $dashletData, $authController, $locale, $currentModule, $import_bean_map, $image_path, $license;
  605. global $user_unique_key, $server_unique_key, $barChartColors, $modules_exempt_from_availability_check, $dictionary, $current_language, $beanList, $beanFiles, $sugar_build, $sugar_codename;
  606. global $timedate, $login_error; // cn: bug 13855 - timedate not available to classic views.
  607. if (!empty($this->module))
  608. $currentModule = $this->module;
  609. require_once ($file);
  610. }
  611. protected function _displayLoginJS()
  612. {
  613. global $sugar_config, $timedate;
  614. if(isset($this->bean->module_dir)){
  615. echo "<script>var module_sugar_grp1 = '{$this->bean->module_dir}';</script>";
  616. }
  617. if(isset($_REQUEST['action'])){
  618. echo "<script>var action_sugar_grp1 = '{$_REQUEST['action']}';</script>";
  619. }
  620. echo '<script>jscal_today = 1000*' . $timedate->asUserTs($timedate->getNow()) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
  621. if (!is_file(sugar_cached("include/javascript/sugar_grp1.js"))) {
  622. $_REQUEST['root_directory'] = ".";
  623. require_once("jssource/minify_utils.php");
  624. ConcatenateFiles(".");
  625. }
  626. echo getVersionedScript('cache/include/javascript/sugar_grp1_jquery.js');
  627. echo getVersionedScript('cache/include/javascript/sugar_grp1_yui.js');
  628. echo getVersionedScript('cache/include/javascript/sugar_grp1.js');
  629. echo getVersionedScript('include/javascript/calendar.js');
  630. echo <<<EOQ
  631. <script>
  632. if ( typeof(SUGAR) == 'undefined' ) {SUGAR = {}};
  633. if ( typeof(SUGAR.themes) == 'undefined' ) SUGAR.themes = {};
  634. </script>
  635. EOQ;
  636. if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
  637. echo getVersionedScript('modules/Sync/headersync.js');
  638. }
  639. /**
  640. * Get JS validation code for views
  641. */
  642. public static function getJavascriptValidation()
  643. {
  644. global $timedate;
  645. $cal_date_format = $timedate->get_cal_date_format();
  646. $timereg = $timedate->get_regular_expression($timedate->get_time_format());
  647. $datereg = $timedate->get_regular_expression($timedate->get_date_format());
  648. $date_pos = '';
  649. foreach ($datereg['positions'] as $type => $pos) {
  650. if (empty($date_pos)) {
  651. $date_pos .= "'$type': $pos";
  652. } else {
  653. $date_pos .= ",'$type': $pos";
  654. }
  655. }
  656. $time_separator = $timedate->timeSeparator();
  657. $hour_offset = $timedate->getUserUTCOffset() * 60;
  658. // Add in the number formatting styles here as well, we have been handling this with individual modules.
  659. require_once ('modules/Currencies/Currency.php');
  660. list ($num_grp_sep, $dec_sep) = get_number_seperators();
  661. $the_script = "<script type=\"text/javascript\">\n" . "\tvar time_reg_format = '" .
  662. $timereg['format'] . "';\n" . "\tvar date_reg_format = '" .
  663. $datereg['format'] . "';\n" . "\tvar date_reg_positions = { $date_pos };\n" .
  664. "\tvar time_separator = '$time_separator';\n" .
  665. "\tvar cal_date_format = '$cal_date_format';\n" .
  666. "\tvar time_offset = $hour_offset;\n" . "\tvar num_grp_sep = '$num_grp_sep';\n" .
  667. "\tvar dec_sep = '$dec_sep';\n" . "</script>";
  668. return $the_script;
  669. }
  670. /**
  671. * Called from process(). This method will display the correct javascript.
  672. */
  673. protected function _displayJavascript()
  674. {
  675. global $locale, $sugar_config, $timedate;
  676. if ($this->_getOption('show_javascript')) {
  677. if (!$this->_getOption('show_header')) {
  678. $langHeader = get_language_header();
  679. echo <<<EOHTML
  680. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  681. <html {$langHeader}>
  682. <head>
  683. EOHTML;
  684. }
  685. $js_vars = array(
  686. "sugar_cache_dir" => "cache/",
  687. );
  688. if(isset($this->bean->module_dir)){
  689. $js_vars['module_sugar_grp1'] = $this->bean->module_dir;
  690. }
  691. if(isset($_REQUEST['action'])){
  692. $js_vars['action_sugar_grp1'] = $_REQUEST['action'];
  693. }
  694. echo '<script>jscal_today = 1000*' . $timedate->asUserTs($timedate->getNow()) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
  695. if (!is_file(sugar_cached("include/javascript/sugar_grp1.js")) || !is_file(sugar_cached("include/javascript/sugar_grp1_yui.js")) || !is_file(sugar_cached("include/javascript/sugar_grp1_jquery.js"))) {
  696. $_REQUEST['root_directory'] = ".";
  697. require_once("jssource/minify_utils.php");
  698. ConcatenateFiles(".");
  699. }
  700. echo getVersionedScript('cache/include/javascript/sugar_grp1_jquery.js');
  701. echo getVersionedScript('cache/include/javascript/sugar_grp1_yui.js');
  702. echo getVersionedScript('cache/include/javascript/sugar_grp1.js');
  703. echo getVersionedScript('include/javascript/calendar.js');
  704. // output necessary config js in the top of the page
  705. $config_js = $this->getSugarConfigJS();
  706. if(!empty($config_js)){
  707. echo "<script>\n".implode("\n", $config_js)."</script>\n";
  708. }
  709. if ( isset($sugar_config['email_sugarclient_listviewmaxselect']) ) {
  710. echo "<script>SUGAR.config.email_sugarclient_listviewmaxselect = {$GLOBALS['sugar_config']['email_sugarclient_listviewmaxselect']};</script>";
  711. }
  712. $image_server = (defined('TEMPLATE_URL'))?TEMPLATE_URL . '/':'';
  713. echo '<script type="text/javascript">SUGAR.themes.image_server="' . $image_server . '";</script>'; // cn: bug 12274 - create session-stored key to defend against CSRF
  714. echo '<script type="text/javascript">var name_format = "' . $locale->getLocaleFormatMacro() . '";</script>';
  715. echo self::getJavascriptValidation();
  716. if (!is_file(sugar_cached('jsLanguage/') . $GLOBALS['current_language'] . '.js')) {
  717. require_once ('include/language/jsLanguage.php');
  718. jsLanguage::createAppStringsCache($GLOBALS['current_language']);
  719. }
  720. echo getVersionedScript('cache/jsLanguage/'. $GLOBALS['current_language'] . '.js', $GLOBALS['sugar_config']['js_lang_version']);
  721. echo $this->_getModLanguageJS();
  722. if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
  723. echo getVersionedScript('modules/Sync/headersync.js');
  724. //echo out the $js_vars variables as javascript variables
  725. echo "<script type='text/javascript'>\n";
  726. foreach($js_vars as $var=>$value)
  727. {
  728. echo "var {$var} = '{$value}';\n";
  729. }
  730. echo "</script>\n";
  731. }
  732. }
  733. protected function _getModLanguageJS(){
  734. if (!is_file(sugar_cached('jsLanguage/') . $this->module . '/' . $GLOBALS['current_language'] . '.js')) {
  735. require_once ('include/language/jsLanguage.php');
  736. jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']);
  737. }
  738. return getVersionedScript("cache/jsLanguage/{$this->module}/". $GLOBALS['current_language'] . '.js', $GLOBALS['sugar_config']['js_lang_version']);
  739. }
  740. /**
  741. * Called from process(). This method will display the footer on the page.
  742. */
  743. public function displayFooter()
  744. {
  745. if (empty($this->responseTime)) {
  746. $this->_calculateFooterMetrics();
  747. }
  748. global $sugar_config;
  749. global $app_strings;
  750. global $mod_strings;
  751. $themeObject = SugarThemeRegistry::current();
  752. //decide whether or not to show themepicker, default is to show
  753. $showThemePicker = true;
  754. if (isset($sugar_config['showThemePicker'])) {
  755. $showThemePicker = $sugar_config['showThemePicker'];
  756. }
  757. echo "<!-- crmprint -->";
  758. $jsalerts = new jsAlerts();
  759. if ( !isset($_SESSION['isMobile']) )
  760. echo $jsalerts->getScript();
  761. $ss = new Sugar_Smarty();
  762. $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
  763. $ss->assign('MOD',return_module_language($GLOBALS['current_language'], 'Users'));
  764. $bottomLinkList = array();
  765. if (isset($this->action) && $this->action != "EditView") {
  766. $bottomLinkList['print'] = array($app_strings['LNK_PRINT'] => getPrintLink());
  767. }
  768. $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => 'javascript:SUGAR.util.top();');
  769. $bottomLinksStr = "";
  770. foreach($bottomLinkList as $key => $value) {
  771. foreach($value as $text => $link) {
  772. $href = $link;
  773. if(substr($link, 0, 11) == "javascript:") {
  774. $onclick = " onclick=\"".substr($link,11)."\"";
  775. $href = "javascript:void(0)";
  776. } else {
  777. $onclick = "";
  778. }
  779. $imageURL = SugarThemeRegistry::current()->getImageURL($key.'.gif');
  780. $bottomLinksStr .= "<a href=\"{$href}\"";
  781. $bottomLinksStr .= (isset($onclick)) ? $onclick : "";
  782. $bottomLinksStr .= "><img src='{$imageURL}' alt=''>"; //keeping alt blank on purpose for 508 (text will be read instead)
  783. $bottomLinksStr .= " ".$text."</a>";
  784. }
  785. }
  786. $ss->assign("BOTTOMLINKS",$bottomLinksStr);
  787. if (SugarConfig::getInstance()->get('calculate_response_time', false))
  788. $ss->assign('STATISTICS',$this->_getStatistics());
  789. // Under the License referenced above, you are required to leave in all copyright statements in both
  790. // the code and end-user application.
  791. $copyright = '&copy; 2004-2012 SugarCRM Inc. The Program is provided AS IS, without warranty. Licensed under <a href="LICENSE.txt" target="_blank" class="copyRightLink">AGPLv3</a>.<br>This program is free software; you can redistribute it and/or modify it under the terms of the <br><a href="LICENSE.txt" target="_blank" class="copyRightLink"> GNU Affero General Public License version 3</a> as published by the Free Software Foundation, including the additional permission set forth in the source code header.<br>';
  792. // The interactive user interfaces in modified source and object code
  793. // versions of this program must display Appropriate Legal Notices, as
  794. // required under Section 5 of the GNU General Public License version
  795. // 3. In accordance with Section 7(b) of the GNU General Public License
  796. // version 3, these Appropriate Legal Notices must retain the display
  797. // of the "Powered by SugarCRM" logo. If the display of the logo is
  798. // not reasonably feasible for technical reasons, the Appropriate
  799. // Legal Notices must display the words "Powered by SugarCRM".
  800. $attribLinkImg = "<img style='margin-top: 2px' border='0' width='120' height='34' src='include/images/poweredby_sugarcrm_65.png' alt='Powered By SugarCRM'>\n";
  801. // handle resizing of the company logo correctly on the fly
  802. $companyLogoURL = $themeObject->getImageURL('company_logo.png');
  803. $companyLogoURL_arr = explode('?', $companyLogoURL);
  804. $companyLogoURL = $companyLogoURL_arr[0];
  805. $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes');
  806. if(!empty($company_logo_attributes)) {
  807. $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]);
  808. $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]);
  809. $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]);
  810. }
  811. else {
  812. // Always need to md5 the file
  813. $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL));
  814. list($width,$height) = getimagesize($companyLogoURL);
  815. if ( $width > 212 || $height > 40 ) {
  816. $resizePctWidth = ($width - 212)/212;
  817. $resizePctHeight = ($height - 40)/40;
  818. if ( $resizePctWidth > $resizePctHeight )
  819. $resizeAmount = $width / 212;
  820. else
  821. $resizeAmount = $height / 40;
  822. $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount)));
  823. $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount)));
  824. }
  825. else {
  826. $ss->assign("COMPANY_LOGO_WIDTH", $width);
  827. $ss->assign("COMPANY_LOGO_HEIGHT", $height);
  828. }
  829. // Let's cache the results
  830. sugar_cache_put('company_logo_attributes',
  831. array(
  832. $ss->get_template_vars("COMPANY_LOGO_MD5"),
  833. $ss->get_template_vars("COMPANY_LOGO_WIDTH"),
  834. $ss->get_template_vars("COMPANY_LOGO_HEIGHT")
  835. )
  836. );
  837. }
  838. $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5"));
  839. // Bug 38594 - Add in Trademark wording
  840. $copyright .= 'SugarCRM is a trademark of SugarCRM, Inc. All other company and product names may be trademarks of the respective companies with which they are associated.<br />';
  841. //rrs bug: 20923 - if this image does not exist as per the license, then the proper image will be displayed regardless, so no need
  842. //to display an empty image here.
  843. if(file_exists('include/images/poweredby_sugarcrm_65.png')){
  844. $copyright .= $attribLinkImg;
  845. }
  846. // End Required Image
  847. $ss->assign('COPYRIGHT',$copyright);
  848. $ss->display(SugarThemeRegistry::current()->getTemplate('footer.tpl'));
  849. }
  850. /**
  851. * Called from process(). This method will display subpanels.
  852. */
  853. protected function _displaySubPanels()
  854. {
  855. if (isset($this->bean) && !empty($this->bean->id) && (file_exists('modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/Ext/Layoutdefs/layoutdefs.ext.php'))) {
  856. $GLOBALS['focus'] = $this->bean;
  857. require_once ('include/SubPanel/SubPanelTiles.php');
  858. $subpanel = new SubPanelTiles($this->bean, $this->module);
  859. echo $subpanel->display();
  860. }
  861. }
  862. protected function _buildModuleList()
  863. {
  864. if (!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader']))
  865. $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
  866. }
  867. /**
  868. * private method used in process() to determine the value of a passed in option
  869. *
  870. * @param string option - the option that we want to know the valye of
  871. * @param bool default - what the default value should be if we do not find the option
  872. *
  873. * @return bool - the value of the option
  874. */
  875. protected function _getOption(
  876. $option,
  877. $default = false
  878. )
  879. {
  880. if (!empty($this->options) && isset($this->options['show_all'])) {
  881. return $this->options['show_all'];
  882. } elseif (!empty($this->options) && isset($this->options[$option])) {
  883. return $this->options[$option];
  884. } else return $default;
  885. }
  886. /**
  887. * track
  888. * Private function to track information about the view request
  889. */
  890. private function _track()
  891. {
  892. if (empty($this->responseTime)) {
  893. $this->_calculateFooterMetrics();
  894. }
  895. if (empty($GLOBALS['current_user']->id)) {
  896. return;
  897. }
  898. $trackerManager = TrackerManager::getInstance();
  899. $trackerManager->save();
  900. }
  901. /**
  902. * Checks to see if the module name passed is valid; dies if it is not
  903. */
  904. protected function _checkModule()
  905. {
  906. if(!empty($this->module) && !file_exists('modules/'.$this->module)){
  907. $error = str_replace("[module]", "$this->module", $GLOBALS['app_strings']['ERR_CANNOT_FIND_MODULE']);
  908. $GLOBALS['log']->fatal($error);
  909. echo $error;
  910. die();
  911. }
  912. }
  913. public function renderJavascript()
  914. {
  915. if ($this->action !== 'Login')
  916. $this->_displayJavascript();
  917. else
  918. $this->_displayLoginJS();
  919. }
  920. private function _calculateFooterMetrics()
  921. {
  922. $endTime = microtime(true);
  923. $deltaTime = $endTime - $GLOBALS['startTime'];
  924. $this->responseTime = number_format(round($deltaTime, 2), 2);
  925. // Print out the resources used in constructing the page.
  926. $this->fileResources = count(get_included_files());
  927. }
  928. private function _getStatistics()
  929. {
  930. $endTime = microtime(true);
  931. $deltaTime = $endTime - $GLOBALS['startTime'];
  932. $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . ' ' . number_format(round($deltaTime, 2), 2) . ' ' . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS'];
  933. $return = $response_time_string;
  934. // $return .= '<br />';
  935. if (!empty($GLOBALS['sugar_config']['show_page_resources'])) {
  936. // Print out the resources used in constructing the page.
  937. $included_files = get_included_files();
  938. // take all of the included files and make a list that does not allow for duplicates based on case
  939. // I believe the full get_include_files result set appears to have one entry for each file in real
  940. // case, and one entry in all lower case.
  941. $list_of_files_case_insensitive = array();
  942. foreach($included_files as $key => $name) {
  943. // preserve the first capitalization encountered.
  944. $list_of_files_case_insensitive[mb_strtolower($name) ] = $name;
  945. }
  946. $return .= $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_RESOURCES'] . '(' . DBManager::getQueryCount() . ',' . sizeof($list_of_files_case_insensitive) . ')<br>';
  947. // Display performance of the internal and external caches....
  948. $cacheStats = SugarCache::instance()->getCacheStats();
  949. $return .= "External cache (hits/total=ratio) local ({$cacheStats['localHits']}/{$cacheStats['requests']}=" . round($cacheStats['localHits']*100/$cacheStats['requests'], 0) . "%)";
  950. $return .= " external ({$cacheStats['externalHits']}/{$cacheStats['requests']}=" . round($cacheStats['externalHits']*100/$cacheStats['requests'], 0) . "%)<br />";
  951. $return .= " misses ({$cacheStats['misses']}/{$cacheStats['requests']}=" . round($cacheStats['misses']*100/$cacheStats['requests'], 0) . "%)<br />";
  952. }
  953. $return .= $this->logMemoryStatistics();
  954. return $return;
  955. }
  956. /**
  957. * logMemoryStatistics
  958. *
  959. * This function returns a string message containing the memory statistics as well as writes to the memory_usage.log
  960. * file the memory statistics for the SugarView invocation.
  961. *
  962. * @param $newline String of newline character to use (defaults to </ br>)
  963. * @return $message String formatted message about memory statistics
  964. */
  965. protected function logMemoryStatistics($newline='<br>')
  966. {
  967. $log_message = '';
  968. if(!empty($GLOBALS['sugar_config']['log_memory_usage']))
  969. {
  970. if(function_exists('memory_get_usage'))
  971. {
  972. $memory_usage = memory_get_usage();
  973. $bytes = $GLOBALS['app_strings']['LBL_SERVER_MEMORY_BYTES'];
  974. $data = array($memory_usage, $bytes);
  975. $log_message = string_format($GLOBALS['app_strings']['LBL_SERVER_MEMORY_USAGE'], $data) . $newline;
  976. }
  977. if(function_exists('memory_get_peak_usage'))
  978. {
  979. $memory_peak_usage = memory_get_peak_usage();
  980. $bytes = $GLOBALS['app_strings']['LBL_SERVER_MEMORY_BYTES'];
  981. $data = array($memory_peak_usage, $bytes);
  982. $log_message .= string_format($GLOBALS['app_strings']['LBL_SERVER_PEAK_MEMORY_USAGE'], $data) . $newline;
  983. }
  984. if(!empty($log_message))
  985. {
  986. $data = array
  987. (
  988. !empty($this->module) ? $this->module : $GLOBALS['app_strings']['LBL_LINK_NONE'],
  989. !empty($this->action) ? $this->action : $GLOBALS['app_strings']['LBL_LINK_NONE'],
  990. );
  991. $output = string_format($GLOBALS['app_strings']['LBL_SERVER_MEMORY_LOG_MESSAGE'], $data) . $newline;
  992. $output .= $log_message;
  993. $fp = fopen("memory_usage.log", "ab");
  994. fwrite($fp, $output);
  995. fclose($fp);
  996. }
  997. }
  998. return $log_message;
  999. }
  1000. /**
  1001. * Loads the module shortcuts menu
  1002. *
  1003. * @param $module string optional, can specify module to retrieve menu for if not the current one
  1004. * @return array module menu
  1005. */
  1006. public function getMenu(
  1007. $module = null
  1008. )
  1009. {
  1010. global $current_language, $current_user, $mod_strings, $app_strings, $module_menu;
  1011. if ( empty($module) )

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