]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarCharts/SugarChart.php
Release 6.2.0
[Github/sugarcrm.git] / include / SugarCharts / SugarChart.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
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.
13  * 
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
17  * details.
18  * 
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
22  * 02110-1301 USA.
23  * 
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.
26  * 
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.
30  * 
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  ********************************************************************************/
37
38
39 class SugarChart {
40
41         private $db;
42         protected $ss;
43         var $forceHideDataGroupLink = false;
44         var $data_set = array();
45         var $display_data = array();
46         var $chart_properties = array();
47         var $chart_yAxis = array();
48         var $group_by = array();
49         var $super_set = array();
50         var $colors_list = array();
51         var $base_url = array();
52         var $url_params = array();
53         
54         var $currency_symbol;
55         var $thousands_symbol;
56         var $is_currency;
57         var $supports_image_export = false;
58         var $print_html_legend_pdf = false;
59         var $image_export_type = "";
60         
61         public function __construct() {
62                 $this->db = &DBManagerFactory::getInstance();
63                 $this->ss = new Sugar_Smarty();
64                 
65                 $this->chart_yAxis['yMin'] = 0;         
66                 $this->chart_yAxis['yMax'] = 0;
67                 
68                 
69                 if ($GLOBALS['current_user']->getPreference('currency')){
70                     
71             $currency = new Currency();
72             $currency->retrieve($GLOBALS['current_user']->getPreference('currency'));
73             $this->div = $currency->conversion_rate;
74             $this->currency_symbol = $currency->symbol;
75         }
76         else{
77                 $this->currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol'];
78                         $this->div = 1;
79                         $this->is_currency = false;
80         }
81         $this->image_export_type = (extension_loaded('gd') && function_exists('gd_info')) ? "png" : "jpg";
82         }
83         
84         function getData($query){
85                 $result = $this->db->query($query);
86                 
87                 $row = $this->db->fetchByAssoc($result);
88                 
89                 while ($row != null){
90                         $this->data_set[] = $row;
91                         $row = $this->db->fetchByAssoc($result);
92                 }
93         }
94         
95         function constructBaseURL(){
96                 $numParams = 0;
97                 $url = 'index.php?';
98                 
99                 foreach ($this->base_url as $param => $value){
100                         if ($numParams == 0){
101                                 $url .= $param . '=' . $value;
102                         }
103                         else{
104                                 $url .= '&' .$param . '=' .$value;
105                         }
106                         $numParams++;
107                 }
108
109                 return $url;
110         }
111         
112         function constructURL(){
113                 $url = $this->constructBaseURL();
114                 foreach ($this->url_params as $param => $value){
115                         if ($param == 'assigned_user_id') $param = 'assigned_user_id[]';
116                         if (is_array($value)){
117                                 foreach($value as $multiple){
118                                         $url .= '&' . $param . '=' . urlencode($multiple);
119                                 }
120                         }
121                         else{
122                                 $url .= '&' . $param . '=' . urlencode($value);
123                         }
124                 }
125                 return $url;
126         }
127         
128         function setData($dataSet){
129                 $this->data_set = $dataSet;
130         }
131         
132         function setProperties($title, $subtitle, $type, $legend='on', $labels='value', $print='on'){
133                 $this->chart_properties['title'] = $title;
134                 $this->chart_properties['subtitle'] = $subtitle;
135                 $this->chart_properties['type'] = $type;
136                 $this->chart_properties['legend'] = $legend;
137                 $this->chart_properties['labels'] = $labels;
138         }
139         
140         function setDisplayProperty($property, $value){
141                 $this->chart_properties[$property] = $value;
142         }
143         
144         function setColors($colors = array()){
145                 $this->colors_list = $colors;
146         }
147         
148     /**
149      * returns the header for the constructed xml file for sugarcharts
150          * 
151      * @param   nothing
152      * @return  string $header XML header
153      */
154         function xmlHeader(){
155                 $header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
156                 $header .= "<sugarcharts version=\"1.0\">\n";
157                 
158                 return $header;
159         }
160
161         /**
162      * returns the footer for the constructed xml file for sugarcharts
163          * 
164      * @param   nothing
165      * @return  string $footer XML footer
166      */
167         function xmlFooter(){
168                 $footer = "</sugarcharts>";
169                 
170                 return $footer;
171         }
172
173         /**
174      * returns the properties tag for the constructed xml file for sugarcharts
175          * 
176      * @param   nothing
177      * @return  string $properties XML properties tag
178      */ 
179         function xmlProperties(){       
180                 // open the properties tag
181                 $properties = $this->tab("<properties>",1);
182                 
183                 // grab the property and value from the chart_properties variable
184                 foreach ($this->chart_properties as $key => $value){
185                         $properties .= $this->tab("<$key>$value</$key>",2);
186                 }
187                 
188                 if (!empty($this->colors_list)){
189                         // open the colors tag
190                         $properties .= $this->tab("<colors>",2);
191                         foreach ($this->colors_list as $color){
192                                 $properties .= $this->tab("<color>$color</color>",3);
193                         }
194                         
195                         // close the colors tag
196                         $properties .= $this->tab("</colors>",2);
197                 }
198                 
199                 // close the properties tag
200                 $properties .= $this->tab("</properties>",1);
201                 
202                 return $properties;
203         }
204         
205         /**
206      * returns the y-axis values for the chart
207          * 
208      * @param   nothing
209      * @return  string $yAxis XML yAxis tag
210      */ 
211         function xmlYAxis(){
212                 $this->chart_yAxis['yStep'] = '100';
213                 $this->chart_yAxis['yLog'] = '1';
214                 $this->chart_yAxis['yMax'] = $this->is_currency ? $this->convertCurrency($this->chart_yAxis['yMax']) : $this->chart_yAxis['yMax'];
215                 $max = $this->chart_yAxis['yMax'];
216                 $exp = ($max == 0) ? 1 : floor(log10($max));
217                 $baseval = $max / pow(10, $exp);
218                 
219                 // steps will be 10^n, 2*10^n, 5*10^n (where n >= 0)
220                 if ($baseval > 0 && $baseval <= 1){
221                         $step = 2 * pow(10, $exp-1);
222                 }
223                 else if ($baseval > 1 && $baseval <= 3){
224                         $step = 5 * pow(10, $exp-1);
225                 }               
226                 else if ($baseval > 3 && $baseval <= 6){
227                         $step = 10 * pow(10, $exp-1);
228                 }       
229                 else if ($baseval > 6 && $baseval <= 10){
230                         $step = 20 * pow(10, $exp-1);
231                 }       
232
233                 // edge cases for values less than 10
234                 if ($max == 0 || $step < 1){
235                         $step = 1;
236                 }
237         
238                 $this->chart_yAxis['yStep'] = $step;
239                 
240                 // to compensate, the yMax should be at least one step above the max value
241                         $this->chart_yAxis['yMax'] += $this->chart_yAxis['yStep'];
242                 
243                 $yAxis = $this->tab("<yAxis>" ,1);
244                 
245                 foreach ($this->chart_yAxis as $key => $value){
246                         $yAxis .= $this->tabValue("{$key}",$value, 2);
247                 }
248                 
249                 $yAxis .= $this->tab("</yAxis>" ,1);
250                 
251                 return $yAxis;
252         }
253
254         /**
255      * returns the total amount value for the group by field
256          * 
257      * @param   group by field
258      * @return  int $total total value
259      */ 
260         function calculateTotal($group_by){
261                 $total = 0;     
262                 
263                 for($i =0; $i < count($this->data_set); $i++){
264                         if ($this->data_set[$i][$this->group_by[0]] == $group_by){
265                                 $total += $this->data_set[$i]['total'];
266                         }
267                 }               
268                 return $total;
269         }
270
271         /**
272      * returns text with tabs appended before it
273          * 
274      * @param   string $str input string
275          *                      int $depth number of times to tab
276      * @return  string with tabs appended before it
277      */ 
278         function tab($str, $depth){
279                 return str_repeat("\t", $depth) . $str . "\n";  
280         }
281         /**
282      * returns text with tabs appended before it
283          * 
284      * @param   string $str xml tag
285                         int $tagFormat 2 = open and close tag, 1 = close, 0 = open
286                         sting $value input string
287          *                      int $depth number of times to tab
288      * @return  string with tabs appended before it
289      */         
290         
291         function tabValue($tag,$value,$depth) {
292
293                         return $this->tab("<{$tag}>".htmlspecialchars($value,ENT_QUOTES)."</{$tag}>",$depth);
294
295         }
296         /**
297      * returns xml data format
298          * 
299      * @param   none
300      * @return  string with xml data format
301      */         
302         function processData(){
303                 $data = array();
304
305                 $group_by = $this->group_by[0];
306                 if (isset($this->group_by[1])){
307                         $drill_down = $this->group_by[1];
308                 }
309                 
310                 $prev_group_by = '';
311
312                 for($i =0; $i < count($this->data_set); $i++){
313                         if ($this->data_set[$i][$group_by] != $prev_group_by){
314                                 $prev_group_by = $this->data_set[$i][$group_by];
315                                 $data[$this->data_set[$i][$group_by]] = array();
316                         }
317             
318             $data[$this->data_set[$i][$group_by]][] = $this->data_set[$i];
319                         
320                         // push new item onto legend items list
321                         if (isset($drill_down)){
322                                 if (!in_array($this->data_set[$i][$drill_down], $this->super_set)){
323                                         $this->super_set[] = $this->data_set[$i][$drill_down];
324                                 }
325                         }
326                 }       
327
328                 return $data;
329         }
330         
331         function processDataGroup($tablevel, $title, $value, $label, $link){
332                 $link = $this->forceHideDataGroupLink ? '' : $link;
333                 $data = $this->tab('<group>',$tablevel);
334                 $data .= $this->tabValue('title',$title,$tablevel+1);
335                 $data .= $this->tabValue('value',$value,$tablevel+1);
336                 $data .= $this->tabValue('label',$label,$tablevel+1);
337                 $data .= $this->tab('<link>' . $link . '</link>',$tablevel+1);
338                 $data .= $this->tab('</group>',$tablevel);
339                 return $data;
340         }
341         
342         function calculateGroupByTotal($dataset){
343                 $total = 0;
344                 
345                 foreach ($dataset as $key => $value){
346                         $total += $value;
347                 }
348                 
349                 return $total;
350         }
351         
352         function calculateSingleBarMax($dataset){
353                 $max = 0;               
354                 foreach ($dataset as $value){
355                         if ($value > $max){
356                                 $max = $value;
357                         }
358                 }
359                 
360                 return $max;
361         }
362
363         /**
364      * returns correct yAxis min/max
365          * 
366      * @param   value to check 
367      * @return  yAxis min and max
368      */                 
369         function checkYAxis($value){
370                 if ($value < $this->chart_yAxis['yMin']){
371                         $this->chart_yAxis['yMin'] = $value;
372                 }
373                 else if ($value > $this->chart_yAxis['yMax']){
374                         $this->chart_yAxis['yMax'] = $value;
375                 }
376         }
377         
378         
379         function convertCurrency($to_convert){
380                 global $locale;
381                 $decimals = '2';
382                 $decimals = $locale->getPrecision();
383                 $amount = ($this->div == 1) ? $to_convert : round($to_convert * $this->div,$decimals);
384                 
385                 return $amount;
386         }
387         
388         function formatNumber($number, $decimals= null, $decimal_point= null, $thousands_sep= null){
389                 global $locale;
390                 if(is_null($decimals)) {
391                         $decimals = $locale->getPrecision();
392                 }
393                 $seps = get_number_seperators();
394                 $thousands_sep = $seps[0];
395                 $decimal_point = $seps[1];
396                 return number_format($number, $decimals, $decimal_point, $thousands_sep);
397         }
398         
399         function getTotal(){
400                 $new_data = $this->processData();
401                 $total = 0;             
402                 foreach ($new_data as $groupByKey => $value){
403                         $total += $this->calculateTotal($groupByKey);
404                 }               
405                 
406                 return $total;
407         }
408
409         function xmlDataForGroupByChart(){
410                 $data = '';             
411                 foreach ($this->data_set as $key => $value){
412                         $amount = $this->is_currency ? $this->convertCurrency($this->calculateGroupByTotal($value)) : $this->calculateGroupByTotal($value);
413             $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount;
414             
415                         $data .= $this->tab('<group>',2);
416                         $data .= $this->tabValue('title',$key,3);
417                         $data .= $this->tabValue('value',$amount,3);
418                         $data .= $this->tabValue('label',$label,3);
419                         $data .= $this->tab('<link></link>',3);
420                         $data .= $this->tab('<subgroups>',3);
421                         
422                         foreach ($value as $k => $v){
423                 $amount = $this->is_currency ? $this->convertCurrency($v) : $v;
424                 $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount)) : $amount;
425                 
426                                 $data .= $this->tab('<group>',4);
427                                 $data .= $this->tabValue('title',$k,5);
428                                 $data .= $this->tabValue('value',$amount,5);
429                                 $data .= $this->tabValue('label',$label,5);
430                                 $data .= $this->tab('<link></link>',5);
431                                 $data .= $this->tab('</group>',4);
432                                 $this->checkYAxis($v);
433                         }
434                         $data .= $this->tab('</subgroups>',3);
435                         $data .= $this->tab('</group>',2);
436                 }
437                 
438                 return $data;           
439         }
440         
441         function xmlDataForGaugeChart(){
442                 $data = '';             
443                 $gaugePosition = $this->data_set[0]['num'];
444                 $this->chart_yAxis['yMax'] = $this->chart_properties['gaugeTarget'];
445                 $this->chart_yAxis['yStep'] = 1;
446                 $data .= $this->processDataGroup(2, 'GaugePosition', $gaugePosition, $gaugePosition, '');
447                 $data .= $this->processGauge($gaugePosition, $this->chart_properties['gaugeTarget']);
448                 
449                 return $data;           
450         }
451         
452         function xmlDataBarChart(){
453                 $data = '';
454                 $max = $this->calculateSingleBarMax($this->data_set);
455                 $this->checkYAxis($max);
456
457                 if (isset($this->group_by[0])){
458                         $group_by = $this->group_by[0];
459                         if (isset($this->group_by[1])){
460                                 $drill_down = $this->group_by[1];
461                         }       
462                 }
463
464                 foreach ($this->data_set as $key => $value){
465                         if ($this->is_currency){
466                                 $value = $this->convertCurrency($value);
467                                 $label = $this->currency_symbol;
468                                 $label .= $this->formatNumber($value);
469                                 $label .= $this->thousands_symbol;
470                         }                               
471                         else{
472                                 $label = $value;
473                         }
474
475                         $data .= $this->tab('<group>', 2);
476                         $data .= $this->tabValue('title',$key, 3);
477                         $data .= $this->tabValue('value',$value, 3);
478                         $data .= $this->tabValue('label',$label, 3);
479                         if (isset($drill_down) && $drill_down){
480                                 if ($this->group_by[0] == 'm'){
481                                         $additional_param = '&date_closed_advanced=' . urlencode($key);                                 
482                                 }
483                                 else{
484                                         $additional_param = "&" . $this->group_by[0] . "=" . urlencode($key);   
485                                 }
486                                 $url = $this->constructURL() . $additional_param;                                       
487                                 
488                                 $data .= $this->tab('<link>' . $url . '</link>', 3);
489                         }                               
490                         $data .= $this->tab('<subgroups>', 3);
491                         $data .= $this->tab('</subgroups>', 3);
492                         $data .= $this->tab('</group>', 2);
493                 }
494                 return $data;   
495         }
496         
497         function xmlDataGenericChart(){
498                 $data = '';
499                 $group_by = $this->group_by[0];
500                 if (isset($this->group_by[1])){
501                         $drill_down = $this->group_by[1];
502                 }               
503                 $new_data = $this->processData();
504
505                 foreach ($new_data as $groupByKey => $value){
506                         $total = $this->calculateTotal($groupByKey);
507                         $this->checkYAxis($total);
508                         
509                         if ($this->group_by[0] == 'm'){
510                                 $additional_param = '&date_closed_advanced=' . urlencode($groupByKey);                                  
511                         }
512                         else{
513                                 $paramValue = (isset($value[0]['key']) && $value[0]['key'] != '') ? $value[0]['key'] : $groupByKey;
514                                 $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;
515                                 $additional_param = "&" . $this->group_by[0] . "=" . urlencode($paramValue);    
516                         }
517                         
518                         $url = $this->constructURL() . $additional_param;
519                         
520                         $amount = $this->is_currency ? $this->convertCurrency($total) : $total;
521                         $label = $this->is_currency ? ($this->currency_symbol . $this->formatNumber($amount) . 'K') : $amount;
522
523                         $data .= $this->tab('<group>',2);
524                         $data .= $this->tabValue('title',$groupByKey,3);
525                         $data .= $this->tabValue('value',$amount,3);
526                         $data .= $this->tabValue('label',$label,3);
527                         $data .= $this->tab('<link>' . $url . '</link>',3);
528                         
529                         $data .= $this->tab('<subgroups>',3);                                           
530                         $processed = array();
531                                 
532                         if (isset($drill_down) && $drill_down != ''){
533                                 for($i =0; $i < count($new_data[$groupByKey]); $i++){
534                                         if ($new_data[$groupByKey][$i][$group_by] == $groupByKey){
535                                                 if ($drill_down == 'user_name'){
536                                                         $drill_down_param = '&assigned_user_id[]=' . urlencode($new_data[$groupByKey][$i]['assigned_user_id']);
537                                                 }
538                                                 else if ($drill_down == 'm'){
539                                                         $drill_down_param = '&date_closed_advanced=' . urlencode($new_data[$groupByKey][$i][$drill_down]);
540                                                 }
541                                                 else{
542                                                         $paramValue = (isset($new_data[$groupByKey][$i][$drill_down."_dom_option"]) && $new_data[$groupByKey][$i][$drill_down."_dom_option"] != '') ? $new_data[$groupByKey][$i][$drill_down."_dom_option"] : $new_data[$groupByKey][$i][$drill_down];
543                                                         $drill_down_param = '&' . $drill_down . '=' . urlencode($paramValue);
544                                                 }
545                                                 
546                                                 if($this->is_currency) {
547                                                   $sub_amount = $this->formatNumber($this->convertCurrency($new_data[$groupByKey][$i]['total']));
548                                                   $sub_amount_formatted = $this->currency_symbol . $sub_amount . 'K';
549                                                   //bug: 38877 - do not format the amount for the value as it breaks the chart
550                                                   $sub_amount = $this->convertCurrency($new_data[$groupByKey][$i]['total']);
551                                                 } else {
552                                                   $sub_amount = $new_data[$groupByKey][$i]['total'];
553                                                   $sub_amount_formatted = $sub_amount;
554                                                 }
555                                                 
556                                                 $data .= $this->processDataGroup(4, $new_data[$groupByKey][$i][$drill_down],
557                                                                                                                     $sub_amount,
558                                                                                                                     $sub_amount_formatted,
559                                                                                                                     $url . $drill_down_param );
560                                                 array_push($processed, $new_data[$groupByKey][$i][$drill_down]);
561                                         }
562                                 }
563                                 $not_processed = array_diff($this->super_set, $processed);
564                                 foreach ($not_processed as $title){
565                                         $data .= $this->processDataGroup(4, $title, 'NULL', '', $url);
566                                 }                       
567                         }
568
569                         $data .= $this->tab('</subgroups>',3);
570                         $data .= $this->tab('</group>',2);
571                 }
572                 return $data;
573         }
574     
575     /**
576      * returns a name for the XML File
577      *
578      * @param string $file_id - unique id to make part of the file name
579      */
580     public static function getXMLFileName(
581          $file_id
582          )
583     {
584         global $sugar_config, $current_user;
585
586         $filename = $sugar_config['tmp_dir']. $current_user->id . '_' . $file_id . '.xml';
587
588         if ( !is_dir(dirname($filename)) )
589             create_cache_directory(str_ireplace($GLOBALS['sugar_config']['cache_dir'],"",$filename));
590
591         return $filename;
592     }
593     
594     public function processXmlData(){
595         $data = '';
596         
597                 if ($this->chart_properties['type'] == 'group by chart'){
598                         $data .= $this->xmlDataForGroupByChart();
599                 }
600                 else if ($this->chart_properties['type'] == 'bar chart' || $this->chart_properties['type'] == 'horizontal bar chart'){
601                         $data .= $this->xmlDataBarChart();                      
602                 }
603                 else{
604                         $data .= $this->xmlDataGenericChart();
605                 }               
606
607                 return $data;
608     }
609      
610         function xmlData(){
611                 $data = $this->tab('<data>',1);
612                 $data .= $this->processXmlData();       
613                 $data .= $this->tab('</data>',1);
614                 
615                 return $data;
616         }
617         
618         /**
619      * function to generate XML and return it
620          * 
621      * @param   none
622      * @return  string $xmlContents with xml information
623      */         
624         function generateXML($xmlDataName = false){
625                 $xmlContents = $this->xmlHeader();              
626                 $xmlContents .= $this->xmlProperties();         
627                 $xmlContents .= $this->xmlData();
628                 $xmlContents .= $this->xmlYAxis();      
629                 $xmlContents .= $this->xmlFooter();
630                 
631                 return $xmlContents;
632         }
633
634         /**
635      * function to save XML contents into a file
636          * 
637      * @param   string $xmlFilename location of the xml file
638          *                      string $xmlContents contents of the xml file
639      * @return  string boolean denoting whether save has failed
640      */                 
641         function saveXMLFile($xmlFilename,$xmlContents) {
642                 global $app_strings;
643                 global $locale;
644                 
645                 $xmlContents = chr(255).chr(254).mb_convert_encoding($xmlContents, 'UTF-16LE', 'UTF-8'); 
646                 
647                 // open file
648                 if (!$fh = sugar_fopen($xmlFilename, 'w')) {
649                         $GLOBALS['log']->debug("Cannot open file ($xmlFilename)");
650                         return;
651                 }
652                 
653                 // write the contents to the file
654                 if (fwrite($fh,$xmlContents) === FALSE) {
655                         $GLOBALS['log']->debug("Cannot write to file ($xmlFilename)");
656                         return false;
657                 }
658         
659                 $GLOBALS['log']->debug("Success, wrote ($xmlContents) to file ($xmlFilename)");
660         
661                 fclose($fh);
662                 return true;
663         }
664
665         /**
666      * generates xml file for Flash charts to use for internationalized instances
667          * 
668      * @param   string $xmlFile location of the XML file to write to
669      * @return  none
670      */ 
671         function generateChartStrings($xmlFile){
672                 global $current_language, $app_list_strings;
673                 
674                 $chartStringsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
675                 $chartStringsXML .= "<sugarlanguage version=\"1.0\">\n";
676                 $chartStringsXML .= $this->tab("<charts>",1);
677                 
678                 if (empty($app_list_strings)) {
679                     //set module and application string arrays based upon selected language
680                         $app_list_strings = return_app_list_strings_language($current_language);
681                 }
682                 
683                 // retrieve the strings defined at include/language/en_us.lang.php
684                 foreach ($app_list_strings['chart_strings'] as $tag => $chart_string){
685                         $chartStringsXML .= $this->tab("<$tag>$chart_string</$tag>",2);
686                 }               
687                 
688                 $chartStringsXML .= $this->tab("</charts>",1);
689                 $chartStringsXML .= "</sugarlanguage>\n";
690                 
691                 $this->saveXMLFile($xmlFile, $chartStringsXML);
692         }
693         
694         /**
695      * wrapper function to return the html code containing the chart in a div
696          * 
697      * @param   string $name    name of the div
698          *                      string $xmlFile location of the XML file
699          *                      string $style   optional additional styles for the div
700      * @return  string returns the html code through smarty
701      */                                 
702         function display($name, $xmlFile, $width='320', $height='480', $resize=false){
703                 
704                 
705                 // generate strings for chart if it does not exist
706                 global $current_language, $theme, $sugar_config,$app_strings;
707                 
708                 $this->app_strings = $app_strings;
709                 $this->chartStringsXML = $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $current_language .'.lang.xml';
710                 if (!file_exists($this->chartStringsXML)){
711                         $this->generateChartStrings($this->chartStringsXML);
712                 }
713                                 
714                 $templateFile = "";                     
715                 return $templateFile;
716         }
717
718         function getDashletScript($id,$xmlFile="") {
719                 
720         $xmlFile = (!$xmlFile) ? $sugar_config['tmp_dir']. $current_user->id . '_' . $this->id . '.xml' : $xmlFile;
721         $chartStringsXML = $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $current_language .'.lang.xml'; 
722         
723         $this->ss->assign('chartName', $id);
724     $this->ss->assign('chartXMLFile', $xmlFile);
725     $this->ss->assign('chartStyleCSS', SugarThemeRegistry::current()->getCSSURL('chart.css'));
726     $this->ss->assign('chartColorsXML', SugarThemeRegistry::current()->getImageURL('sugarColors.xml'));
727     $this->ss->assign('chartLangFile', $GLOBALS['sugar_config']['tmp_dir'].'chart_strings.' . $GLOBALS['current_language'] .'.lang.xml');
728                 
729                 $templateFile = "";
730                 return $templateFile;
731         }
732         
733         
734   /**
735          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.
736          If the data quantity is large, it maybe a little slow.
737     * @param         array $data_set           The data get from database
738                            string $keycolname1      We will sort by this key first
739                            bool $translate1            Whether to trabslate the first column
740                            string $keycolname1      We will sort by this key secondly, and  it can be null, then it will only sort by the first column.
741                            bool $translate1            Whether to trabslate the second column
742                            bool $ifsort2                 Whether to sort by the second column or just translate the second column.
743     * @return        The sorted and translated data.
744    */
745     function sortData($data_set, $keycolname1=null, $translate1=false, $keycolname2=null, $translate2=false, $ifsort2=false) {
746         //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.
747         global $app_list_strings;
748         $sortby1[] = array();
749         foreach ($data_set as $row) {
750             $sortby1[]  = $row[$keycolname1];
751         }
752         $sortby1 = array_unique($sortby1);
753         //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
754         if($translate1) {
755             $temp_sortby1 = array();
756             foreach(array_keys($app_list_strings[$keycolname1.'_dom']) as $sortby1_value) {
757                 if(in_array($sortby1_value, $sortby1)) {
758                     $temp_sortby1[] = $sortby1_value;
759                 }
760             }
761             $sortby1 = $temp_sortby1;
762         }
763         
764         //if(isset($sortby1[0]) && $sortby1[0]=='') unset($sortby1[0]);//the beginning of lead_source_dom is blank.
765         if(isset($sortby1[0]) && $sortby1[0]==array()) unset($sortby1[0]);//the beginning of month after search is blank.
766         
767         if($ifsort2==false) $sortby2=array(0);
768         
769         if($keycolname2!=null) {
770             $sortby2 = array();
771             foreach ($data_set as $row) {
772                 $sortby2[]  = $row[$keycolname2];
773             }
774             //The data is from the database, the sorting should be done in the sql. So I will not do the sort here.
775             $sortby2 = array_unique($sortby2);
776             if($translate2) {
777                 $temp_sortby2 = array();
778                 foreach(array_keys($app_list_strings[$keycolname2.'_dom']) as $sortby2_value) {
779                     if(in_array($sortby2_value, $sortby2)) {
780                         $temp_sortby2[] = $sortby2_value;
781                     }
782                 }
783                 $sortby2 = $temp_sortby2;
784             }
785         }
786         
787         $data=array();
788
789         foreach($sortby1 as $sort1) {
790             foreach($sortby2 as $sort2) {
791                 if($ifsort2) $a=0;
792                 foreach($data_set as $key => $value){
793                     if($value[$keycolname1] == $sort1 && (!$ifsort2 || $value[$keycolname2]== $sort2)) {
794                         if($translate1) {
795                             $value[$keycolname1.'_dom_option'] = $value[$keycolname1];
796                             $value[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$value[$keycolname1]];
797                         }
798                         if($translate2) {
799                             $value[$keycolname2.'_dom_option'] = $value[$keycolname2];
800                             $value[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$value[$keycolname2]];
801                         }
802                         array_push($data, $value);
803                         unset($data_set[$key]);
804                         $a=1;
805                         }
806                 }
807                 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.
808                     $val=array();
809                     $val['total'] = 0;
810                     $val['count'] = 0;
811                     if($translate1) {
812                         $val[$keycolname1] = $app_list_strings[$keycolname1.'_dom'][$sort1];
813                         $val[$keycolname1.'_dom_option'] = $sort1;
814                     }
815                     else {
816                         $val[$keycolname1] = $sort1;                    
817                     }
818                     if($translate2) {
819                         $val[$keycolname2] = $app_list_strings[$keycolname2.'_dom'][$sort2];
820                         $val[$keycolname2.'_dom_option'] = $sort2;                    
821                     }
822                     elseif($keycolname2!=null) {
823                         $val[$keycolname2] = $sort2;
824                     }
825                     array_push($data, $val);
826                 }
827             }  
828         }
829         return $data;
830     }
831     
832     function getChartResources() {
833                 
834                 $resources = "";
835                 return $resources;
836         }
837         
838         function getMySugarChartResources() {
839                 
840                 $mySugarRources = "";
841                 return $mySugarResources;
842         }
843         
844         /**
845      * wrapper function to return chart array after any additional processing
846          * 
847      * @param   array $chartsArray      array of chart config items that need processing
848      * @return  array $chartArray after it has been process
849      */
850         function chartArray($chartsArray) {
851
852                 return $chartsArray;
853         }
854
855 } // end class def