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-2013 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 ********************************************************************************/
47 var $forceHideDataGroupLink = false;
48 var $data_set = array();
49 var $display_data = array();
50 var $chart_properties = array();
51 var $chart_yAxis = array();
52 var $group_by = array();
53 var $super_set = array();
54 var $colors_list = array();
55 var $base_url = array();
56 var $url_params = array();
59 var $thousands_symbol;
61 var $supports_image_export = false;
62 var $print_html_legend_pdf = false;
63 var $image_export_type = "";
65 public function __construct() {
66 $this->db = &DBManagerFactory::getInstance();
67 $this->ss = new Sugar_Smarty();
69 $this->chart_yAxis['yMin'] = 0;
70 $this->chart_yAxis['yMax'] = 0;
73 if ($GLOBALS['current_user']->getPreference('currency')){
75 $currency = new Currency();
76 $currency->retrieve($GLOBALS['current_user']->getPreference('currency'));
77 $this->div = $currency->conversion_rate;
78 $this->currency_symbol = $currency->symbol;
81 $this->currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol'];
83 $this->is_currency = false;
85 $this->image_export_type = (extension_loaded('gd') && function_exists('gd_info')) ? "png" : "jpg";
88 function getData($query){
89 $result = $this->db->query($query);
91 $row = $this->db->fetchByAssoc($result);
94 $this->data_set[] = $row;
95 $row = $this->db->fetchByAssoc($result);
99 function constructBaseURL(){
103 foreach ($this->base_url as $param => $value){
104 if ($numParams == 0){
105 $url .= $param . '=' . $value;
108 $url .= '&' .$param . '=' .$value;
116 function constructURL(){
117 $url = $this->constructBaseURL();
118 foreach ($this->url_params as $param => $value){
119 if ($param == 'assigned_user_id') $param = 'assigned_user_id[]';
120 if (is_array($value)){
121 foreach($value as $multiple){
122 $url .= '&' . $param . '=' . urlencode($multiple);
126 $url .= '&' . $param . '=' . urlencode($value);
132 function setData($dataSet){
133 $this->data_set = $dataSet;
136 function setProperties($title, $subtitle, $type, $legend='on', $labels='value', $print='on', $thousands = false)
138 $this->chart_properties['title'] = $title;
139 $this->chart_properties['subtitle'] = $subtitle;
140 $this->chart_properties['type'] = $type;
141 $this->chart_properties['legend'] = $legend;
142 $this->chart_properties['labels'] = $labels;
143 $this->chart_properties['thousands'] = $thousands;
146 function setDisplayProperty($property, $value){
147 $this->chart_properties[$property] = $value;
150 function setColors($colors = array()){
151 $this->colors_list = $colors;
155 * returns the header for the constructed xml file for sugarcharts
158 * @return string $header XML header
160 function xmlHeader(){
161 $header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
162 $header .= "<sugarcharts version=\"1.0\">\n";
168 * returns the footer for the constructed xml file for sugarcharts
171 * @return string $footer XML footer
173 function xmlFooter(){
174 $footer = "</sugarcharts>";
180 * returns the properties tag for the constructed xml file for sugarcharts
183 * @return string $properties XML properties tag
185 function xmlProperties(){
186 // open the properties tag
187 $properties = $this->tab("<properties>",1);
189 // grab the property and value from the chart_properties variable
190 foreach ($this->chart_properties as $key => $value){
191 if(is_array($value)) continue;
192 $properties .= $this->tab("<$key>$value</$key>",2);
195 if (!empty($this->colors_list)){
196 // open the colors tag
197 $properties .= $this->tab("<colors>",2);
198 foreach ($this->colors_list as $color){
199 $properties .= $this->tab("<color>$color</color>",3);
202 // close the colors tag
203 $properties .= $this->tab("</colors>",2);
206 // close the properties tag
207 $properties .= $this->tab("</properties>",1);
213 * returns the y-axis values for the chart
216 * @return string $yAxis XML yAxis tag
219 $this->chart_yAxis['yStep'] = '100';
220 $this->chart_yAxis['yLog'] = '1';
221 $this->chart_yAxis['yMax'] = $this->is_currency ? $this->convertCurrency($this->chart_yAxis['yMax']) : $this->chart_yAxis['yMax'];
222 $max = $this->chart_yAxis['yMax'];
223 $exp = ($max == 0) ? 1 : floor(log10($max));
224 $baseval = $max / pow(10, $exp);
226 // steps will be 10^n, 2*10^n, 5*10^n (where n >= 0)
227 if ($baseval > 0 && $baseval <= 1){
228 $step = 2 * pow(10, $exp-1);
230 else if ($baseval > 1 && $baseval <= 3){
231 $step = 5 * pow(10, $exp-1);
233 else if ($baseval > 3 && $baseval <= 6){
234 $step = 10 * pow(10, $exp-1);
236 else if ($baseval > 6 && $baseval <= 10){
237 $step = 20 * pow(10, $exp-1);
240 // edge cases for values less than 10
241 if ($max == 0 || $step < 1){
245 $this->chart_yAxis['yStep'] = $step;
247 // to compensate, the yMax should be at least one step above the max value
248 $this->chart_yAxis['yMax'] += $this->chart_yAxis['yStep'];
250 $yAxis = $this->tab("<yAxis>" ,1);
252 foreach ($this->chart_yAxis as $key => $value){
253 $yAxis .= $this->tabValue("{$key}",$value, 2);
256 $yAxis .= $this->tab("</yAxis>" ,1);
262 * returns the total amount value for the group by field
264 * @param group by field
265 * @return int $total total value
267 function calculateTotal($group_by){
270 for($i =0; $i < count($this->data_set); $i++){
271 if ($this->data_set[$i][$this->group_by[0]] == $group_by){
272 $total += $this->data_set[$i]['total'];
279 * returns text with tabs appended before it
281 * @param string $str input string
282 * int $depth number of times to tab
283 * @return string with tabs appended before it
285 function tab($str, $depth){
286 return str_repeat("\t", $depth) . $str . "\n";
289 * returns text with tabs appended before it
291 * @param string $str xml tag
292 int $tagFormat 2 = open and close tag, 1 = close, 0 = open
293 sting $value input string
294 * int $depth number of times to tab
295 * @return string with tabs appended before it
298 function tabValue($tag,$value,$depth) {
300 return $this->tab("<{$tag}>".htmlspecialchars($value,ENT_QUOTES)."</{$tag}>",$depth);
304 * returns xml data format
307 * @return string with xml data format
309 function processData(){
312 $group_by = $this->group_by[0];
313 if (isset($this->group_by[1])){
314 $drill_down = $this->group_by[1];
319 for($i =0; $i < count($this->data_set); $i++){
320 if ($this->data_set[$i][$group_by] != $prev_group_by){
321 $prev_group_by = $this->data_set[$i][$group_by];
322 $data[$this->data_set[$i][$group_by]] = array();
325 $data[$this->data_set[$i][$group_by]][] = $this->data_set[$i];
327 // push new item onto legend items list
328 if (isset($drill_down)){
329 if (!in_array($this->data_set[$i][$drill_down], $this->super_set)){
330 $this->super_set[] = $this->data_set[$i][$drill_down];
338 function processDataGroup($tablevel, $title, $value, $label, $link){
339 $link = $this->forceHideDataGroupLink ? '' : $link;
340 $data = $this->tab('<group>',$tablevel);
341 $data .= $this->tabValue('title',$title,$tablevel+1);
342 $data .= $this->tabValue('value',$value,$tablevel+1);
343 $data .= $this->tabValue('label',$label,$tablevel+1);
344 $data .= $this->tab('<link>' . $link . '</link>',$tablevel+1);
345 $data .= $this->tab('</group>',$tablevel);
349 function calculateGroupByTotal($dataset){
352 foreach ($dataset as $key => $value){
359 function calculateSingleBarMax($dataset){
361 foreach ($dataset as $value){
371 * returns correct yAxis min/max
373 * @param value to check
374 * @return yAxis min and max
376 function checkYAxis($value){
377 if ($value < $this->chart_yAxis['yMin']){
378 $this->chart_yAxis['yMin'] = $value;
380 else if ($value > $this->chart_yAxis['yMax']){
381 $this->chart_yAxis['yMax'] = $value;
387 * Convert the amount given to the User's currency.
389 * TODO make this use the Currency module to convert from dollars and make
392 * @param float $to_convert
393 * The amount to be converted.
396 * The amount converted in the User's current currency.
398 * @see Currency::convertFromDollar()
399 * @see SugarChart::__construct()
401 function convertCurrency($to_convert)
405 $decimals = $locale->getPrecision();
406 $amount = round($to_convert * $this->div, $decimals);
411 function formatNumber($number, $decimals= null, $decimal_point= null, $thousands_sep= null){
413 if(is_null($decimals)) {
414 $decimals = $locale->getPrecision();
416 $seps = get_number_seperators();
417 $thousands_sep = $seps[0];
418 $decimal_point = $seps[1];
419 return number_format($number, $decimals, $decimal_point, $thousands_sep);
423 $new_data = $this->processData();
425 foreach ($new_data as $groupByKey => $value){
426 $total += $this->calculateTotal($groupByKey);
432 function xmlDataForGroupByChart(){
434 foreach ($this->data_set as $key => $value){
435 $amount = $this->is_currency ? $this->convertCurrency($this->calculateGroupByTotal($value)) : $this->calculateGroupByTotal($value);
436 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount;
438 $data .= $this->tab('<group>',2);
439 $data .= $this->tabValue('title',$key,3);
440 $data .= $this->tabValue('value',$amount,3);
441 $data .= $this->tabValue('label',$label,3);
442 $data .= $this->tab('<link></link>',3);
443 $data .= $this->tab('<subgroups>',3);
445 foreach ($value as $k => $v){
446 $amount = $this->is_currency ? $this->convertCurrency($v) : $v;
447 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount;
449 $data .= $this->tab('<group>',4);
450 $data .= $this->tabValue('title',$k,5);
451 $data .= $this->tabValue('value',$amount,5);
452 $data .= $this->tabValue('label',$label,5);
453 $data .= $this->tab('<link></link>',5);
454 $data .= $this->tab('</group>',4);
455 $this->checkYAxis($v);
457 $data .= $this->tab('</subgroups>',3);
458 $data .= $this->tab('</group>',2);
464 function xmlDataForGaugeChart(){
466 $gaugePosition = $this->data_set[0]['num'];
467 $this->chart_yAxis['yMax'] = $this->chart_properties['gaugeTarget'];
468 $this->chart_yAxis['yStep'] = 1;
469 $data .= $this->processDataGroup(2, 'GaugePosition', $gaugePosition, $gaugePosition, '');
470 if (isset($this->chart_properties['gaugePhases']) && is_array($this->chart_properties['gaugePhases'])) {
471 $data .= $this->processGauge($gaugePosition, $this->chart_properties['gaugeTarget'], $this->chart_properties['gaugePhases']);
473 $data .= $this->processGauge($gaugePosition, $this->chart_properties['gaugeTarget']);
479 function xmlDataBarChart(){
481 $max = $this->calculateSingleBarMax($this->data_set);
482 $this->checkYAxis($max);
484 if (isset($this->group_by[0])){
485 $group_by = $this->group_by[0];
486 if (isset($this->group_by[1])){
487 $drill_down = $this->group_by[1];
491 foreach ($this->data_set as $key => $value){
492 if ($this->is_currency){
493 $value = $this->convertCurrency($value);
494 $label = $this->currency_symbol;
495 $label .= $this->formatNumber($value);
496 $label .= $this->thousands_symbol;
502 $data .= $this->tab('<group>', 2);
503 $data .= $this->tabValue('title',$key, 3);
504 $data .= $this->tabValue('value',$value, 3);
505 $data .= $this->tabValue('label',$label, 3);
506 if (isset($drill_down) && $drill_down){
507 if ($this->group_by[0] == 'm') {
508 $additional_param = '&date_closed_advanced=' . urlencode($key);
509 } else if ( $this->group_by[0] == 'sales_stage' ) {
510 $additional_param = '&sales_stage_advanced[]='.urlencode(array_search($key,$GLOBALS['app_list_strings']['sales_stage_dom']));
512 $additional_param = "&" . $this->group_by[0] . "=" . urlencode($key);
514 $url = $this->constructURL() . $additional_param;
516 $data .= $this->tab('<link>' . $url . '</link>', 3);
518 $data .= $this->tab('<subgroups>', 3);
519 $data .= $this->tab('</subgroups>', 3);
520 $data .= $this->tab('</group>', 2);
525 function xmlDataGenericChart(){
527 $group_by = $this->group_by[0];
528 if (isset($this->group_by[1])){
529 $drill_down = $this->group_by[1];
531 $new_data = $this->processData();
533 foreach ($new_data as $groupByKey => $value){
534 $total = $this->calculateTotal($groupByKey);
535 $this->checkYAxis($total);
537 if ($this->group_by[0] == 'm'){
538 $additional_param = '&date_closed_advanced=' . urlencode($groupByKey);
541 $paramValue = (isset($value[0]['key']) && $value[0]['key'] != '') ? $value[0]['key'] : $groupByKey;
542 $paramValue = (isset($value[0][$this->group_by[0]."_dom_option"]) && $value[0][$this->group_by[0]."_dom_option"] != '') ? $value[0][$this->group_by[0]."_dom_option"] : $paramValue;
543 $additional_param = "&" . $this->group_by[0] . "=" . urlencode($paramValue);
546 $url = $this->constructURL() . $additional_param;
548 $amount = $this->is_currency ? $this->convertCurrency($total) : $total;
549 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount) . 'K') : $amount;
551 $data .= $this->tab('<group>',2);
552 $data .= $this->tabValue('title',$groupByKey,3);
553 $data .= $this->tabValue('value',$amount,3);
554 $data .= $this->tabValue('label',$label,3);
555 $data .= $this->tab('<link>' . $url . '</link>',3);
557 $data .= $this->tab('<subgroups>',3);
558 $processed = array();
560 if (isset($drill_down) && $drill_down != ''){
562 * Bug 44696 - Ivan D.
563 * We have to iterate users in order since they are in the super_set for every group.
564 * This is required to display the correct links for each user in a drill down chart.
566 foreach ($this->super_set as $superSetKey => $superSetValue)
568 $objectInSaleStage = false;
569 foreach ($value as $internalKey => $internalValue)
571 if ($internalValue[$drill_down] == $superSetValue)
573 $objectInSaleStage = $value[$internalKey];
577 if ($objectInSaleStage)
579 if (isset($objectInSaleStage[$group_by]) && $objectInSaleStage[$group_by] == $groupByKey)
581 if ($drill_down == 'user_name')
583 $drill_down_param = '&assigned_user_id[]=' . urlencode($objectInSaleStage['assigned_user_id']);
585 else if ($drill_down == 'm')
587 $drill_down_param = '&date_closed_advanced=' . urlencode($objectInSaleStage[$drill_down]);
591 $paramValue = (isset($objectInSaleStage[$drill_down . "_dom_option"]) && $objectInSaleStage[$drill_down . "_dom_option"] != '') ? $objectInSaleStage[$drill_down . "_dom_option"] : $objectInSaleStage[$drill_down];
592 $drill_down_param = '&' . $drill_down . '=' . urlencode($paramValue);
595 if ($this->is_currency)
597 $sub_amount = $this->formatNumber($this->convertCurrency($objectInSaleStage['total']));
598 $sub_amount_formatted = $this->currency_symbol . $sub_amount . 'K';
599 //bug: 38877 - do not format the amount for the value as it breaks the chart
600 $sub_amount = $this->convertCurrency($objectInSaleStage['total']);
604 $sub_amount = $objectInSaleStage['total'];
605 $sub_amount_formatted = $sub_amount;
608 $data .= $this->processDataGroup(4, $objectInSaleStage[$drill_down], $sub_amount, $sub_amount_formatted, $url . $drill_down_param);
612 $data .= $this->nullGroup($superSetValue, $url);
618 $data .= $this->nullGroup($superSetValue, $url);
623 $data .= $this->tab('</subgroups>',3);
624 $data .= $this->tab('</group>',2);
632 * This function sets a null group by clause
634 * @param $sugarSetValue Mixed value
635 * @param $url String value of URL for the link
637 private function nullGroup($superSetValue, $url) {
638 return $this->processDataGroup(4, $superSetValue, 'NULL', '', $url);
643 * returns a name for the XML File
645 * @param string $file_id - unique id to make part of the file name
647 public static function getXMLFileName($file_id)
649 create_cache_directory("xml/".$GLOBALS['current_user']->getUserPrivGuid() . "_{$file_id}.xml");
651 return sugar_cached("xml/"). $GLOBALS['current_user']->getUserPrivGuid() . "_" . $file_id . ".xml";
654 public function processXmlData(){
657 if ($this->chart_properties['type'] == 'group by chart'){
658 $data .= $this->xmlDataForGroupByChart();
660 else if ($this->chart_properties['type'] == 'bar chart' || $this->chart_properties['type'] == 'horizontal bar chart'){
661 $data .= $this->xmlDataBarChart();
664 $data .= $this->xmlDataGenericChart();
671 $data = $this->tab('<data>',1);
672 $data .= $this->processXmlData();
673 $data .= $this->tab('</data>',1);
679 * function to generate XML and return it
682 * @return string $xmlContents with xml information
684 function generateXML($xmlDataName = false){
685 $xmlContents = $this->xmlHeader();
686 $xmlContents .= $this->xmlProperties();
687 $xmlContents .= $this->xmlData();
688 $xmlContents .= $this->xmlYAxis();
689 $xmlContents .= $this->xmlFooter();
695 * function to save XML contents into a file
697 * @param string $xmlFilename location of the xml file
698 * string $xmlContents contents of the xml file
699 * @return string boolean denoting whether save has failed
701 function saveXMLFile($xmlFilename,$xmlContents) {
705 $xmlContents = chr(255).chr(254).$GLOBALS['locale']->translateCharset($xmlContents, 'UTF-8', 'UTF-16LE');
707 // Create dir if it doesn't exist
708 $dir = dirname($xmlFilename);
709 if (!sugar_is_dir($dir))
711 sugar_mkdir($dir, null, true);
715 if (!$fh = sugar_fopen($xmlFilename, 'w')) {
716 $GLOBALS['log']->debug("Cannot open file ($xmlFilename)");
720 // write the contents to the file
721 if (fwrite($fh,$xmlContents) === FALSE) {
722 $GLOBALS['log']->debug("Cannot write to file ($xmlFilename)");
726 $GLOBALS['log']->debug("Success, wrote ($xmlContents) to file ($xmlFilename)");
733 * generates xml file for Flash charts to use for internationalized instances
735 * @param string $xmlFile location of the XML file to write to
738 function generateChartStrings($xmlFile){
739 global $current_language, $app_list_strings;
741 $chartStringsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
742 $chartStringsXML .= "<sugarlanguage version=\"1.0\">\n";
743 $chartStringsXML .= $this->tab("<charts>",1);
745 if (empty($app_list_strings)) {
746 //set module and application string arrays based upon selected language
747 $app_list_strings = return_app_list_strings_language($current_language);
750 // retrieve the strings defined at include/language/en_us.lang.php
751 foreach ($app_list_strings['chart_strings'] as $tag => $chart_string){
752 $chartStringsXML .= $this->tab("<$tag>$chart_string</$tag>",2);
755 $chartStringsXML .= $this->tab("</charts>",1);
756 $chartStringsXML .= "</sugarlanguage>\n";
758 $this->saveXMLFile($xmlFile, $chartStringsXML);
762 * wrapper function to return the html code containing the chart in a div
764 * @param string $name name of the div
765 * string $xmlFile location of the XML file
766 * string $style optional additional styles for the div
767 * @return string returns the html code through smarty
769 function display($name, $xmlFile, $width='320', $height='480', $resize=false){
772 // generate strings for chart if it does not exist
773 global $current_language, $theme, $sugar_config,$app_strings;
775 $this->app_strings = $app_strings;
776 $this->chartStringsXML = sugar_cached("xml/").'chart_strings.' . $current_language .'.lang.xml';
777 if (!file_exists($this->chartStringsXML)){
778 $this->generateChartStrings($this->chartStringsXML);
782 return $templateFile;
786 function getDashletScript($id,$xmlFile="") {
788 $xmlFile = (!$xmlFile) ? $sugar_config['tmp_dir']. $current_user->id . '_' . $this->id . '.xml' : $xmlFile;
789 $chartStringsXML = $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $current_language .'.lang.xml';
791 $this->ss->assign('chartName', $id);
792 $this->ss->assign('chartXMLFile', $xmlFile);
793 $this->ss->assign('chartStyleCSS', SugarThemeRegistry::current()->getCSSURL('chart.css'));
794 $this->ss->assign('chartColorsXML', SugarThemeRegistry::current()->getImageURL('sugarColors.xml'));
795 $this->ss->assign('chartLangFile', $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $GLOBALS['current_language'] .'.lang.xml');
798 return $templateFile;
803 This function is used for localize all the characters in the Chart. And it can also sort all the dom_values by the sequence defined in the dom, but this may produce a lot of extra empty data in the xml file, when the chart is sorted by two key cols.
804 If the data quantity is large, it maybe a little slow.
805 * @param array $data_set The data get from database
806 string $keycolname1 We will sort by this key first
807 bool $translate1 Whether to trabslate the first column
808 string $keycolname1 We will sort by this key secondly, and it can be null, then it will only sort by the first column.
809 bool $translate1 Whether to trabslate the second column
810 bool $ifsort2 Whether to sort by the second column or just translate the second column.
811 * @return The sorted and translated data.
813 function sortData($data_set, $keycolname1=null, $translate1=false, $keycolname2=null, $translate2=false, $ifsort2=false) {
814 //You can set whether the columns need to be translated or sorted. It the column needn't to be translated, the sorting must be done in SQL, this function will not do the sorting.
815 global $app_list_strings;
816 $sortby1[] = array();
817 foreach ($data_set as $row) {
818 $sortby1[] = $row[$keycolname1];
820 $sortby1 = array_unique($sortby1);
821 //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
823 $temp_sortby1 = array();
824 foreach(array_keys($app_list_strings[$keycolname1.'_dom']) as $sortby1_value) {
825 if(in_array($sortby1_value, $sortby1)) {
826 $temp_sortby1[] = $sortby1_value;
829 $sortby1 = $temp_sortby1;
832 //if(isset($sortby1[0]) && $sortby1[0]=='') unset($sortby1[0]);//the beginning of lead_source_dom is blank.
833 if(isset($sortby1[0]) && $sortby1[0]==array()) unset($sortby1[0]);//the beginning of month after search is blank.
835 if($ifsort2==false) $sortby2=array(0);
837 if($keycolname2!=null) {
839 foreach ($data_set as $row) {
840 $sortby2[] = $row[$keycolname2];
842 //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
843 $sortby2 = array_unique($sortby2);
845 $temp_sortby2 = array();
846 foreach(array_keys($app_list_strings[$keycolname2.'_dom']) as $sortby2_value) {
847 if(in_array($sortby2_value, $sortby2)) {
848 $temp_sortby2[] = $sortby2_value;
851 $sortby2 = $temp_sortby2;
857 foreach($sortby1 as $sort1) {
858 foreach($sortby2 as $sort2) {
860 foreach($data_set as $key => $value){
861 if($value[$keycolname1] == $sort1 && (!$ifsort2 || $value[$keycolname2]== $sort2)) {
863 $value[$keycolname1.'_dom_option'] = $value[$keycolname1];
864 $value[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$value[$keycolname1]];
867 $value[$keycolname2.'_dom_option'] = $value[$keycolname2];
868 $value[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$value[$keycolname2]];
870 array_push($data, $value);
871 unset($data_set[$key]);
875 if($ifsort2 && $a==0) {//Add 0 for sorting by the second column, if the first row doesn't have a certain col, it will fill the column with 0.
880 $val[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$sort1];
881 $val[$keycolname1.'_dom_option'] = $sort1;
884 $val[$keycolname1] = $sort1;
887 $val[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$sort2];
888 $val[$keycolname2.'_dom_option'] = $sort2;
890 elseif($keycolname2!=null) {
891 $val[$keycolname2] = $sort2;
893 array_push($data, $val);
900 function getChartResources() {
906 function getMySugarChartResources() {
907 $mySugarResources = "";
908 return $mySugarResources;
912 * wrapper function to return chart array after any additional processing
914 * @param array $chartsArray array of chart config items that need processing
915 * @return array $chartArray after it has been process
917 function chartArray($chartsArray) {