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-2012 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 $properties .= $this->tab("<$key>$value</$key>",2);
194 if (!empty($this->colors_list)){
195 // open the colors tag
196 $properties .= $this->tab("<colors>",2);
197 foreach ($this->colors_list as $color){
198 $properties .= $this->tab("<color>$color</color>",3);
201 // close the colors tag
202 $properties .= $this->tab("</colors>",2);
205 // close the properties tag
206 $properties .= $this->tab("</properties>",1);
212 * returns the y-axis values for the chart
215 * @return string $yAxis XML yAxis tag
218 $this->chart_yAxis['yStep'] = '100';
219 $this->chart_yAxis['yLog'] = '1';
220 $this->chart_yAxis['yMax'] = $this->is_currency ? $this->convertCurrency($this->chart_yAxis['yMax']) : $this->chart_yAxis['yMax'];
221 $max = $this->chart_yAxis['yMax'];
222 $exp = ($max == 0) ? 1 : floor(log10($max));
223 $baseval = $max / pow(10, $exp);
225 // steps will be 10^n, 2*10^n, 5*10^n (where n >= 0)
226 if ($baseval > 0 && $baseval <= 1){
227 $step = 2 * pow(10, $exp-1);
229 else if ($baseval > 1 && $baseval <= 3){
230 $step = 5 * pow(10, $exp-1);
232 else if ($baseval > 3 && $baseval <= 6){
233 $step = 10 * pow(10, $exp-1);
235 else if ($baseval > 6 && $baseval <= 10){
236 $step = 20 * pow(10, $exp-1);
239 // edge cases for values less than 10
240 if ($max == 0 || $step < 1){
244 $this->chart_yAxis['yStep'] = $step;
246 // to compensate, the yMax should be at least one step above the max value
247 $this->chart_yAxis['yMax'] += $this->chart_yAxis['yStep'];
249 $yAxis = $this->tab("<yAxis>" ,1);
251 foreach ($this->chart_yAxis as $key => $value){
252 $yAxis .= $this->tabValue("{$key}",$value, 2);
255 $yAxis .= $this->tab("</yAxis>" ,1);
261 * returns the total amount value for the group by field
263 * @param group by field
264 * @return int $total total value
266 function calculateTotal($group_by){
269 for($i =0; $i < count($this->data_set); $i++){
270 if ($this->data_set[$i][$this->group_by[0]] == $group_by){
271 $total += $this->data_set[$i]['total'];
278 * returns text with tabs appended before it
280 * @param string $str input string
281 * int $depth number of times to tab
282 * @return string with tabs appended before it
284 function tab($str, $depth){
285 return str_repeat("\t", $depth) . $str . "\n";
288 * returns text with tabs appended before it
290 * @param string $str xml tag
291 int $tagFormat 2 = open and close tag, 1 = close, 0 = open
292 sting $value input string
293 * int $depth number of times to tab
294 * @return string with tabs appended before it
297 function tabValue($tag,$value,$depth) {
299 return $this->tab("<{$tag}>".htmlspecialchars($value,ENT_QUOTES)."</{$tag}>",$depth);
303 * returns xml data format
306 * @return string with xml data format
308 function processData(){
311 $group_by = $this->group_by[0];
312 if (isset($this->group_by[1])){
313 $drill_down = $this->group_by[1];
318 for($i =0; $i < count($this->data_set); $i++){
319 if ($this->data_set[$i][$group_by] != $prev_group_by){
320 $prev_group_by = $this->data_set[$i][$group_by];
321 $data[$this->data_set[$i][$group_by]] = array();
324 $data[$this->data_set[$i][$group_by]][] = $this->data_set[$i];
326 // push new item onto legend items list
327 if (isset($drill_down)){
328 if (!in_array($this->data_set[$i][$drill_down], $this->super_set)){
329 $this->super_set[] = $this->data_set[$i][$drill_down];
337 function processDataGroup($tablevel, $title, $value, $label, $link){
338 $link = $this->forceHideDataGroupLink ? '' : $link;
339 $data = $this->tab('<group>',$tablevel);
340 $data .= $this->tabValue('title',$title,$tablevel+1);
341 $data .= $this->tabValue('value',$value,$tablevel+1);
342 $data .= $this->tabValue('label',$label,$tablevel+1);
343 $data .= $this->tab('<link>' . $link . '</link>',$tablevel+1);
344 $data .= $this->tab('</group>',$tablevel);
348 function calculateGroupByTotal($dataset){
351 foreach ($dataset as $key => $value){
358 function calculateSingleBarMax($dataset){
360 foreach ($dataset as $value){
370 * returns correct yAxis min/max
372 * @param value to check
373 * @return yAxis min and max
375 function checkYAxis($value){
376 if ($value < $this->chart_yAxis['yMin']){
377 $this->chart_yAxis['yMin'] = $value;
379 else if ($value > $this->chart_yAxis['yMax']){
380 $this->chart_yAxis['yMax'] = $value;
385 function convertCurrency($to_convert){
388 $decimals = $locale->getPrecision();
389 $amount = ($this->div == 1) ? $to_convert : round($to_convert * $this->div,$decimals);
394 function formatNumber($number, $decimals= null, $decimal_point= null, $thousands_sep= null){
396 if(is_null($decimals)) {
397 $decimals = $locale->getPrecision();
399 $seps = get_number_seperators();
400 $thousands_sep = $seps[0];
401 $decimal_point = $seps[1];
402 return number_format($number, $decimals, $decimal_point, $thousands_sep);
406 $new_data = $this->processData();
408 foreach ($new_data as $groupByKey => $value){
409 $total += $this->calculateTotal($groupByKey);
415 function xmlDataForGroupByChart(){
417 foreach ($this->data_set as $key => $value){
418 $amount = $this->is_currency ? $this->convertCurrency($this->calculateGroupByTotal($value)) : $this->calculateGroupByTotal($value);
419 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount;
421 $data .= $this->tab('<group>',2);
422 $data .= $this->tabValue('title',$key,3);
423 $data .= $this->tabValue('value',$amount,3);
424 $data .= $this->tabValue('label',$label,3);
425 $data .= $this->tab('<link></link>',3);
426 $data .= $this->tab('<subgroups>',3);
428 foreach ($value as $k => $v){
429 $amount = $this->is_currency ? $this->convertCurrency($v) : $v;
430 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount;
432 $data .= $this->tab('<group>',4);
433 $data .= $this->tabValue('title',$k,5);
434 $data .= $this->tabValue('value',$amount,5);
435 $data .= $this->tabValue('label',$label,5);
436 $data .= $this->tab('<link></link>',5);
437 $data .= $this->tab('</group>',4);
438 $this->checkYAxis($v);
440 $data .= $this->tab('</subgroups>',3);
441 $data .= $this->tab('</group>',2);
447 function xmlDataForGaugeChart(){
449 $gaugePosition = $this->data_set[0]['num'];
450 $this->chart_yAxis['yMax'] = $this->chart_properties['gaugeTarget'];
451 $this->chart_yAxis['yStep'] = 1;
452 $data .= $this->processDataGroup(2, 'GaugePosition', $gaugePosition, $gaugePosition, '');
453 if (isset($this->chart_properties['gaugePhases']) && is_array($this->chart_properties['gaugePhases'])) {
454 $data .= $this->processGauge($gaugePosition, $this->chart_properties['gaugeTarget'], $this->chart_properties['gaugePhases']);
456 $data .= $this->processGauge($gaugePosition, $this->chart_properties['gaugeTarget']);
462 function xmlDataBarChart(){
464 $max = $this->calculateSingleBarMax($this->data_set);
465 $this->checkYAxis($max);
467 if (isset($this->group_by[0])){
468 $group_by = $this->group_by[0];
469 if (isset($this->group_by[1])){
470 $drill_down = $this->group_by[1];
474 foreach ($this->data_set as $key => $value){
475 if ($this->is_currency){
476 $value = $this->convertCurrency($value);
477 $label = $this->currency_symbol;
478 $label .= $this->formatNumber($value);
479 $label .= $this->thousands_symbol;
485 $data .= $this->tab('<group>', 2);
486 $data .= $this->tabValue('title',$key, 3);
487 $data .= $this->tabValue('value',$value, 3);
488 $data .= $this->tabValue('label',$label, 3);
489 if (isset($drill_down) && $drill_down){
490 if ($this->group_by[0] == 'm') {
491 $additional_param = '&date_closed_advanced=' . urlencode($key);
492 } else if ( $this->group_by[0] == 'sales_stage' ) {
493 $additional_param = '&sales_stage_advanced[]='.urlencode(array_search($key,$GLOBALS['app_list_strings']['sales_stage_dom']));
495 $additional_param = "&" . $this->group_by[0] . "=" . urlencode($key);
497 $url = $this->constructURL() . $additional_param;
499 $data .= $this->tab('<link>' . $url . '</link>', 3);
501 $data .= $this->tab('<subgroups>', 3);
502 $data .= $this->tab('</subgroups>', 3);
503 $data .= $this->tab('</group>', 2);
508 function xmlDataGenericChart(){
510 $group_by = $this->group_by[0];
511 if (isset($this->group_by[1])){
512 $drill_down = $this->group_by[1];
514 $new_data = $this->processData();
516 foreach ($new_data as $groupByKey => $value){
517 $total = $this->calculateTotal($groupByKey);
518 $this->checkYAxis($total);
520 if ($this->group_by[0] == 'm'){
521 $additional_param = '&date_closed_advanced=' . urlencode($groupByKey);
524 $paramValue = (isset($value[0]['key']) && $value[0]['key'] != '') ? $value[0]['key'] : $groupByKey;
525 $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;
526 $additional_param = "&" . $this->group_by[0] . "=" . urlencode($paramValue);
529 $url = $this->constructURL() . $additional_param;
531 $amount = $this->is_currency ? $this->convertCurrency($total) : $total;
532 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount) . 'K') : $amount;
534 $data .= $this->tab('<group>',2);
535 $data .= $this->tabValue('title',$groupByKey,3);
536 $data .= $this->tabValue('value',$amount,3);
537 $data .= $this->tabValue('label',$label,3);
538 $data .= $this->tab('<link>' . $url . '</link>',3);
540 $data .= $this->tab('<subgroups>',3);
541 $processed = array();
543 if (isset($drill_down) && $drill_down != ''){
545 * Bug 44696 - Ivan D.
546 * We have to iterate users in order since they are in the super_set for every group.
547 * This is required to display the correct links for each user in a drill down chart.
549 foreach ($this->super_set as $superSetKey => $superSetValue)
551 $objectInSaleStage = false;
552 foreach ($value as $internalKey => $internalValue)
554 if ($internalValue[$drill_down] == $superSetValue)
556 $objectInSaleStage = $value[$internalKey];
560 if ($objectInSaleStage)
562 if (isset($objectInSaleStage[$group_by]) && $objectInSaleStage[$group_by] == $groupByKey)
564 if ($drill_down == 'user_name')
566 $drill_down_param = '&assigned_user_id[]=' . urlencode($objectInSaleStage['assigned_user_id']);
568 else if ($drill_down == 'm')
570 $drill_down_param = '&date_closed_advanced=' . urlencode($objectInSaleStage[$drill_down]);
574 $paramValue = (isset($objectInSaleStage[$drill_down . "_dom_option"]) && $objectInSaleStage[$drill_down . "_dom_option"] != '') ? $objectInSaleStage[$drill_down . "_dom_option"] : $objectInSaleStage[$drill_down];
575 $drill_down_param = '&' . $drill_down . '=' . urlencode($paramValue);
578 if ($this->is_currency)
580 $sub_amount = $this->formatNumber($this->convertCurrency($objectInSaleStage['total']));
581 $sub_amount_formatted = $this->currency_symbol . $sub_amount . 'K';
582 //bug: 38877 - do not format the amount for the value as it breaks the chart
583 $sub_amount = $this->convertCurrency($objectInSaleStage['total']);
587 $sub_amount = $objectInSaleStage['total'];
588 $sub_amount_formatted = $sub_amount;
591 $data .= $this->processDataGroup(4, $objectInSaleStage[$drill_down], $sub_amount, $sub_amount_formatted, $url . $drill_down_param);
595 $data .= $this->nullGroup($superSetValue, $url);
601 $data .= $this->nullGroup($superSetValue, $url);
606 $data .= $this->tab('</subgroups>',3);
607 $data .= $this->tab('</group>',2);
615 * This function sets a null group by clause
617 * @param $sugarSetValue Mixed value
618 * @param $url String value of URL for the link
620 private function nullGroup($superSetValue, $url) {
621 return $this->processDataGroup(4, $superSetValue, 'NULL', '', $url);
626 * returns a name for the XML File
628 * @param string $file_id - unique id to make part of the file name
630 public static function getXMLFileName(
634 global $sugar_config, $current_user;
636 $filename = sugar_cached("xml/"). $current_user->id . '_' . $file_id . '.xml';
638 if ( !is_dir(dirname($filename)) ) {
639 create_cache_directory("xml");
645 public function processXmlData(){
648 if ($this->chart_properties['type'] == 'group by chart'){
649 $data .= $this->xmlDataForGroupByChart();
651 else if ($this->chart_properties['type'] == 'bar chart' || $this->chart_properties['type'] == 'horizontal bar chart'){
652 $data .= $this->xmlDataBarChart();
655 $data .= $this->xmlDataGenericChart();
662 $data = $this->tab('<data>',1);
663 $data .= $this->processXmlData();
664 $data .= $this->tab('</data>',1);
670 * function to generate XML and return it
673 * @return string $xmlContents with xml information
675 function generateXML($xmlDataName = false){
676 $xmlContents = $this->xmlHeader();
677 $xmlContents .= $this->xmlProperties();
678 $xmlContents .= $this->xmlData();
679 $xmlContents .= $this->xmlYAxis();
680 $xmlContents .= $this->xmlFooter();
686 * function to save XML contents into a file
688 * @param string $xmlFilename location of the xml file
689 * string $xmlContents contents of the xml file
690 * @return string boolean denoting whether save has failed
692 function saveXMLFile($xmlFilename,$xmlContents) {
696 $xmlContents = chr(255).chr(254).$GLOBALS['locale']->translateCharset($xmlContents, 'UTF-8', 'UTF-16LE');
699 if (!$fh = sugar_fopen($xmlFilename, 'w')) {
700 $GLOBALS['log']->debug("Cannot open file ($xmlFilename)");
704 // write the contents to the file
705 if (fwrite($fh,$xmlContents) === FALSE) {
706 $GLOBALS['log']->debug("Cannot write to file ($xmlFilename)");
710 $GLOBALS['log']->debug("Success, wrote ($xmlContents) to file ($xmlFilename)");
717 * generates xml file for Flash charts to use for internationalized instances
719 * @param string $xmlFile location of the XML file to write to
722 function generateChartStrings($xmlFile){
723 global $current_language, $app_list_strings;
725 $chartStringsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
726 $chartStringsXML .= "<sugarlanguage version=\"1.0\">\n";
727 $chartStringsXML .= $this->tab("<charts>",1);
729 if (empty($app_list_strings)) {
730 //set module and application string arrays based upon selected language
731 $app_list_strings = return_app_list_strings_language($current_language);
734 // retrieve the strings defined at include/language/en_us.lang.php
735 foreach ($app_list_strings['chart_strings'] as $tag => $chart_string){
736 $chartStringsXML .= $this->tab("<$tag>$chart_string</$tag>",2);
739 $chartStringsXML .= $this->tab("</charts>",1);
740 $chartStringsXML .= "</sugarlanguage>\n";
742 $this->saveXMLFile($xmlFile, $chartStringsXML);
746 * wrapper function to return the html code containing the chart in a div
748 * @param string $name name of the div
749 * string $xmlFile location of the XML file
750 * string $style optional additional styles for the div
751 * @return string returns the html code through smarty
753 function display($name, $xmlFile, $width='320', $height='480', $resize=false){
756 // generate strings for chart if it does not exist
757 global $current_language, $theme, $sugar_config,$app_strings;
759 $this->app_strings = $app_strings;
760 $this->chartStringsXML = sugar_cached("xml/").'chart_strings.' . $current_language .'.lang.xml';
761 if (!file_exists($this->chartStringsXML)){
762 $this->generateChartStrings($this->chartStringsXML);
766 return $templateFile;
770 function getDashletScript($id,$xmlFile="") {
772 $xmlFile = (!$xmlFile) ? $sugar_config['tmp_dir']. $current_user->id . '_' . $this->id . '.xml' : $xmlFile;
773 $chartStringsXML = $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $current_language .'.lang.xml';
775 $this->ss->assign('chartName', $id);
776 $this->ss->assign('chartXMLFile', $xmlFile);
777 $this->ss->assign('chartStyleCSS', SugarThemeRegistry::current()->getCSSURL('chart.css'));
778 $this->ss->assign('chartColorsXML', SugarThemeRegistry::current()->getImageURL('sugarColors.xml'));
779 $this->ss->assign('chartLangFile', $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $GLOBALS['current_language'] .'.lang.xml');
782 return $templateFile;
787 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.
788 If the data quantity is large, it maybe a little slow.
789 * @param array $data_set The data get from database
790 string $keycolname1 We will sort by this key first
791 bool $translate1 Whether to trabslate the first column
792 string $keycolname1 We will sort by this key secondly, and it can be null, then it will only sort by the first column.
793 bool $translate1 Whether to trabslate the second column
794 bool $ifsort2 Whether to sort by the second column or just translate the second column.
795 * @return The sorted and translated data.
797 function sortData($data_set, $keycolname1=null, $translate1=false, $keycolname2=null, $translate2=false, $ifsort2=false) {
798 //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.
799 global $app_list_strings;
800 $sortby1[] = array();
801 foreach ($data_set as $row) {
802 $sortby1[] = $row[$keycolname1];
804 $sortby1 = array_unique($sortby1);
805 //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
807 $temp_sortby1 = array();
808 foreach(array_keys($app_list_strings[$keycolname1.'_dom']) as $sortby1_value) {
809 if(in_array($sortby1_value, $sortby1)) {
810 $temp_sortby1[] = $sortby1_value;
813 $sortby1 = $temp_sortby1;
816 //if(isset($sortby1[0]) && $sortby1[0]=='') unset($sortby1[0]);//the beginning of lead_source_dom is blank.
817 if(isset($sortby1[0]) && $sortby1[0]==array()) unset($sortby1[0]);//the beginning of month after search is blank.
819 if($ifsort2==false) $sortby2=array(0);
821 if($keycolname2!=null) {
823 foreach ($data_set as $row) {
824 $sortby2[] = $row[$keycolname2];
826 //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
827 $sortby2 = array_unique($sortby2);
829 $temp_sortby2 = array();
830 foreach(array_keys($app_list_strings[$keycolname2.'_dom']) as $sortby2_value) {
831 if(in_array($sortby2_value, $sortby2)) {
832 $temp_sortby2[] = $sortby2_value;
835 $sortby2 = $temp_sortby2;
841 foreach($sortby1 as $sort1) {
842 foreach($sortby2 as $sort2) {
844 foreach($data_set as $key => $value){
845 if($value[$keycolname1] == $sort1 && (!$ifsort2 || $value[$keycolname2]== $sort2)) {
847 $value[$keycolname1.'_dom_option'] = $value[$keycolname1];
848 $value[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$value[$keycolname1]];
851 $value[$keycolname2.'_dom_option'] = $value[$keycolname2];
852 $value[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$value[$keycolname2]];
854 array_push($data, $value);
855 unset($data_set[$key]);
859 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.
864 $val[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$sort1];
865 $val[$keycolname1.'_dom_option'] = $sort1;
868 $val[$keycolname1] = $sort1;
871 $val[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$sort2];
872 $val[$keycolname2.'_dom_option'] = $sort2;
874 elseif($keycolname2!=null) {
875 $val[$keycolname2] = $sort2;
877 array_push($data, $val);
884 function getChartResources() {
890 function getMySugarChartResources() {
891 $mySugarResources = "";
892 return $mySugarResources;
896 * wrapper function to return chart array after any additional processing
898 * @param array $chartsArray array of chart config items that need processing
899 * @return array $chartArray after it has been process
901 function chartArray($chartsArray) {