]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/Dashlets/DashletGeneric.php
Release 6.5.15
[Github/sugarcrm.git] / include / Dashlets / DashletGeneric.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-2013 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 require_once('include/Dashlets/Dashlet.php');
39 require_once('include/ListView/ListViewSmarty.php');
40 require_once('include/generic/LayoutManager.php');
41
42 /**
43  * Generic Dashlet class
44  * @api
45  */
46 class DashletGeneric extends Dashlet {
47    /**
48      * Fields that are searchable
49      * @var array
50      */
51     var $searchFields;
52     /**
53      * Displayable columns (ones available to display)
54      * @var array
55      */
56     var $columns;
57     /**
58      * Bean file used in this Dashlet
59      * @var bean
60      */
61     var $seedBean;
62     /**
63      * collection of filters to apply
64      * @var array
65      */
66     var $filters = null;
67     /**
68      * Number of Rows to display
69      * @var int
70      */
71     var $displayRows = '5';
72     /**
73      * Actual columns to display, will be a subset of $columns
74      * @var array
75      */
76     var $displayColumns = null;
77     /**
78      * Flag to display only the current users's items.
79      * @var bool
80      */
81     var $myItemsOnly = true;
82     /**
83      * Flag to display "myItemsOnly" checkbox in the DashletGenericConfigure.
84      * @var bool
85      */
86     var $showMyItemsOnly = true;
87     /**
88      * location of Smarty template file for display
89      * @var string
90      */
91     var $displayTpl = 'include/Dashlets/DashletGenericDisplay.tpl';
92     /**
93      * location of smarty template file for configuring
94      * @var string
95      */
96     var $configureTpl = 'include/Dashlets/DashletGenericConfigure.tpl';
97     /**
98      * smarty object for the generic configuration template
99      * @var string
100      */
101     var $configureSS;
102     /** search inputs to be populated in configure template.
103      *  modify this after processDisplayOptions, but before displayOptions to modify search inputs
104      *  @var array
105      */
106     var $currentSearchFields;
107     /**
108      * ListView Smarty Class
109      * @var Smarty
110      */
111     var $lvs;
112     var $layoutManager;
113
114     function DashletGeneric($id, $options = null) {
115         parent::Dashlet($id);
116         $this->isConfigurable = true;
117         if(isset($options)) {
118             if(!empty($options['filters'])) $this->filters = $options['filters'];
119             if(!empty($options['title'])) $this->title = $options['title'];
120             if(!empty($options['displayRows'])) $this->displayRows = $options['displayRows'];
121             if(!empty($options['displayColumns'])) $this->displayColumns = $options['displayColumns'];
122             if(isset($options['myItemsOnly'])) $this->myItemsOnly = $options['myItemsOnly'];
123             if(isset($options['autoRefresh'])) $this->autoRefresh = $options['autoRefresh'];
124         }
125
126         $this->layoutManager = new LayoutManager();
127         $this->layoutManager->setAttribute('context', 'Report');
128         // fake a reporter object here just to pass along the db type used in many widgets.
129         // this should be taken out when sugarwidgets change
130         $temp = (object) array('db' => &$GLOBALS['db'], 'report_def_str' => '');
131         $this->layoutManager->setAttributePtr('reporter', $temp);
132         $this->lvs = new ListViewSmarty();
133     }
134
135     /**
136      * Sets up the display options template
137      *
138      * @return string HTML that shows options
139      */
140     function processDisplayOptions() {
141          require_once('include/templates/TemplateGroupChooser.php');
142
143         $this->configureSS = new Sugar_Smarty();
144         // column chooser
145         $chooser = new TemplateGroupChooser();
146
147         $chooser->args['id'] = 'edit_tabs';
148         $chooser->args['left_size'] = 5;
149         $chooser->args['right_size'] = 5;
150         $chooser->args['values_array'][0] = array();
151         $chooser->args['values_array'][1] = array();
152
153         $this->loadCustomMetadata();
154         // Bug 39517 - Don't add custom fields automatically to the available fields to display in the listview
155         //$this->addCustomFields();
156         if($this->displayColumns) {
157              // columns to display
158              foreach($this->displayColumns as $num => $name) {
159                     // defensive code for array being returned
160                     $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir);
161                     if(is_array($translated)) $translated = $this->columns[$name]['label'];
162                     $chooser->args['values_array'][0][$name] = trim($translated, ':');
163              }
164              // columns not displayed
165              foreach(array_diff(array_keys($this->columns), array_values($this->displayColumns)) as $num => $name) {
166                     // defensive code for array being returned
167                     $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir);
168                     if(is_array($translated)) $translated = $this->columns[$name]['label'];
169                     $chooser->args['values_array'][1][$name] = trim($translated, ':');
170              }
171         }
172         else {
173              foreach($this->columns as $name => $val) {
174                 // defensive code for array being returned
175                 $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir);
176                 if(is_array($translated)) $translated = $this->columns[$name]['label'];
177                 if(!empty($val['default']) && $val['default'])
178                     $chooser->args['values_array'][0][$name] = trim($translated, ':');
179                 else
180                     $chooser->args['values_array'][1][$name] = trim($translated, ':');
181             }
182         }
183
184         $chooser->args['left_name'] = 'display_tabs';
185         $chooser->args['right_name'] = 'hide_tabs';
186         $chooser->args['max_left'] = '6';
187
188         $chooser->args['left_label'] =  $GLOBALS['app_strings']['LBL_DISPLAY_COLUMNS'];
189         $chooser->args['right_label'] =  $GLOBALS['app_strings']['LBL_HIDE_COLUMNS'];
190         $chooser->args['title'] =  '';
191         $this->configureSS->assign('columnChooser', $chooser->display());
192
193         $query = false;
194         $count = 0;
195
196         if(!is_array($this->filters)) {
197             // use default search params
198             $this->filters = array();
199             foreach($this->searchFields as $name => $params) {
200                 if(!empty($params['default']))
201                     $this->filters[$name] = $params['default'];
202             }
203         }
204         $currentSearchFields = array();
205         foreach($this->searchFields as $name=>$params) {
206             if(!empty($name)) {
207                 $name = strtolower($name);
208                 $currentSearchFields[$name] = array();
209                 $widgetDef = $this->seedBean->field_defs[$name];
210                 if($widgetDef['name'] == 'assigned_user_name') $widgetDef['name'] = 'assigned_user_id';
211                 //bug 39170 - begin
212                 if($widgetDef['name'] == 'created_by_name') $name = $widgetDef['name'] = 'created_by';
213                 if($widgetDef['name'] == 'modified_by_name') $name = $widgetDef['name'] = 'modified_user_id';
214                 //bug 39170 - end
215                 if($widgetDef['type']=='enum'){
216                    $filterNotSelected = array(); // we need to have some value otherwise '' or null values make -none- to be selected by default
217                 }else{
218                    $filterNotSelected = '';
219                 }
220                 $widgetDef['input_name0'] = empty($this->filters[$name]) ? $filterNotSelected : $this->filters[$name];
221
222                 $currentSearchFields[$name]['label'] = !empty($params['label']) ? translate($params['label'], $this->seedBean->module_dir) : translate($widgetDef['vname'], $this->seedBean->module_dir);
223                 $currentSearchFields[$name]['input'] = $this->layoutManager->widgetDisplayInput($widgetDef, true, (empty($this->filters[$name]) ? '' : $this->filters[$name]));
224             }
225             else { // ability to create spacers in input fields
226                 $currentSearchFields['blank' + $count]['label'] = '';
227                 $currentSearchFields['blank' + $count]['input'] = '';
228                 $count++;
229             }
230         }
231         $this->currentSearchFields = $currentSearchFields;
232
233         $this->configureSS->assign('strings', array('general' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_GENERAL'],
234                                      'filters' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_FILTERS'],
235                                      'myItems' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY'],
236                                      'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'],
237                                      'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'],
238                                      'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'],
239                                      'clear' => $GLOBALS['app_strings']['LBL_CLEAR_BUTTON_LABEL'],
240                                      'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'],
241                                      ));
242         $this->configureSS->assign('id', $this->id);
243         $this->configureSS->assign('showMyItemsOnly', $this->showMyItemsOnly);
244         $this->configureSS->assign('myItemsOnly', $this->myItemsOnly);
245         $this->configureSS->assign('searchFields', $this->currentSearchFields);
246         $this->configureSS->assign('showClearButton', $this->isConfigPanelClearShown);
247         // title
248         $this->configureSS->assign('dashletTitle', $this->title);
249
250         // display rows
251         $displayRowOptions = $GLOBALS['sugar_config']['dashlet_display_row_options'];
252         $this->configureSS->assign('displayRowOptions', $displayRowOptions);
253         $this->configureSS->assign('displayRowSelect', $this->displayRows);
254
255         if($this->isAutoRefreshable()) {
256                 $this->configureSS->assign('isRefreshable', true);
257                         $this->configureSS->assign('autoRefreshOptions', $this->getAutoRefreshOptions());
258                         $this->configureSS->assign('autoRefreshSelect', $this->autoRefresh);
259                 }
260     }
261     /**
262      * Displays the options for this Dashlet
263      *
264      * @return string HTML that shows options
265      */
266     function displayOptions() {
267         $this->processDisplayOptions();
268         return parent::displayOptions() . $this->configureSS->fetch($this->configureTpl);
269     }
270
271     function buildWhere() {
272         global $current_user;
273
274         $returnArray = array();
275
276         if(!is_array($this->filters)) {
277             // use defaults
278             $this->filters = array();
279             foreach($this->searchFields as $name => $params) {
280                 if(!empty($params['default']))
281                     $this->filters[$name] = $params['default'];
282             }
283         }
284         foreach($this->filters as $name=>$params) {
285             if(!empty($params)) {
286                 if($name == 'assigned_user_id' && $this->myItemsOnly) continue; // don't handle assigned user filter if filtering my items only
287                 $widgetDef = $this->seedBean->field_defs[$name];
288
289                 $widgetClass = $this->layoutManager->getClassFromWidgetDef($widgetDef, true);
290                 $widgetDef['table'] = $this->seedBean->table_name;
291                 $widgetDef['table_alias'] = $this->seedBean->table_name;
292                 if(!empty($widgetDef['source']) && $widgetDef['source'] == 'custom_fields') {
293                     $widgetDef['table'] = $this->seedBean->table_name."_cstm";
294                     $widgetDef['table_alias'] = $widgetDef['table'];
295                 }
296                 switch($widgetDef['type']) {// handle different types
297                     case 'date':
298                     case 'datetime':
299                     case 'datetimecombo':
300                         if(is_array($params) && !empty($params)) {
301                             if(!empty($params['date']))
302                                 $widgetDef['input_name0'] = $params['date'];
303                             $filter = 'queryFilter' . $params['type'];
304                         }
305                         else {
306                             $filter = 'queryFilter' . $params;
307                         }
308                         array_push($returnArray, $widgetClass->$filter($widgetDef, true));
309                         break;
310                     case 'assigned_user_name':
311                         // This type runs through the SugarWidgetFieldname class, and needs a little extra help to make it through
312                         if ( ! isset($widgetDef['column_key']) ) {
313                             $widgetDef['column_key'] = $name;
314                         }
315                         // No break here, we want to run through the default handler
316                     case 'relate':
317                         if (isset($widgetDef['link']) && $this->seedBean->load_relationship($widgetDef['link'])) {
318                             $widgetDef['module'] = $this->seedBean->$widgetDef['link']->focus->module_name;
319                             $widgetDef['link'] = $this->seedBean->$widgetDef['link']->getRelationshipObject()->name;
320                         }
321                         // No break - run through the default handler
322                     default:
323                         $widgetDef['input_name0'] = $params;
324                         if(is_array($params) && !empty($params)) { // handle array query
325                             array_push($returnArray, $widgetClass->queryFilterone_of($widgetDef, false));
326                         }
327                         else {
328                             array_push($returnArray, $widgetClass->queryFilterStarts_With($widgetDef, true));
329                         }
330                         $widgetDef['input_name0'] = $params;
331                     break;
332                 }
333             }
334         }
335
336         if($this->myItemsOnly) array_push($returnArray, $this->seedBean->table_name . '.' . "assigned_user_id = '" . $current_user->id . "'");
337
338         return $returnArray;
339     }
340
341         protected function loadCustomMetadata()
342         {
343         $customMetadate = 'custom/modules/'.$this->seedBean->module_dir.'/metadata/dashletviewdefs.php';
344         if ( file_exists ( $customMetadate )){
345                 require($customMetadate);
346                         $this->searchFields = $dashletData[$this->seedBean->module_dir.'Dashlet']['searchFields'];
347                         foreach($this->searchFields  as $key =>$def){
348                                 if($key == 'assigned_user_name'){
349                                         $this->searchFields['assigned_user_id'] = $def;
350                                         unset($this->searchFields['assigned_user_name'] );
351                                         break;
352                                 }
353                         }
354
355                 $this->columns = $dashletData[$this->seedBean->module_dir.'Dashlet']['columns'];
356         }
357         }
358
359     /**
360      * Does all dashlet processing, here's your chance to modify the rows being displayed!
361      */
362     function process($lvsParams = array()) {
363         $currentSearchFields = array();
364         $configureView = true; // configure view or regular view
365         $query = false;
366         $whereArray = array();
367         $lvsParams['massupdate'] = false;
368
369                 $this->loadCustomMetadata();
370         $this->addCustomFields();
371         // apply filters
372         if(isset($this->filters) || $this->myItemsOnly) {
373             $whereArray = $this->buildWhere();
374         }
375
376         $this->lvs->export = false;
377         $this->lvs->multiSelect = false;
378         // columns
379         $displayColumns = array();
380         if(!empty($this->displayColumns)) { // use user specified columns
381                 foreach($this->displayColumns as $name => $val) {
382                 $displayColumns[strtoupper($val)] = $this->columns[$val];
383                 $displayColumns[strtoupper($val)]['label'] = trim($displayColumns[strtoupper($val)]['label'], ':');// strip : at the end of headers
384             }
385         }
386         else if (isset($this->columns)){
387            // use the default
388             foreach($this->columns as $name => $val) {
389                 if(!empty($val['default']) && $val['default']) {
390                     $displayColumns[strtoupper($name)] = $val;
391                     $displayColumns[strtoupper($name)]['label'] = trim($displayColumns[strtoupper($name)]['label'], ':');
392                 }
393             }
394         }
395         $this->lvs->displayColumns = $displayColumns;
396
397
398         $this->lvs->lvd->setVariableName($this->seedBean->object_name, array());
399         $lvdOrderBy = $this->lvs->lvd->getOrderBy(); // has this list been ordered, if not use default
400
401         $nameRelatedFields = array();
402
403         //bug: 44592 - dashlet sort order was not being preserved between logins
404         if(!empty($lvsParams['orderBy']) && !empty($lvsParams['sortOrder']))
405         {
406             $lvsParams['overrideOrder'] = true;
407         }
408         else
409         {
410             if(empty($lvdOrderBy['orderBy'])) {
411                 foreach($displayColumns as $colName => $colParams) {
412                     if(!empty($colParams['defaultOrderColumn'])) {
413                         $lvsParams['overrideOrder'] = true;
414                         $lvsParams['orderBy'] = $colName;
415                         $lvsParams['sortOrder'] = $colParams['defaultOrderColumn']['sortOrder'];
416                     }
417                 }
418             }
419         }
420                 // Check for 'last_name' column sorting with related fields (last_name, first_name)
421                 // See ListViewData.php for actual sorting change.
422                 if ($lvdOrderBy['orderBy'] == 'last_name' && !empty($displayColumns['NAME']) && !empty($displayColumns['NAME']['related_fields']) &&
423                         in_array('last_name', $displayColumns['NAME']['related_fields']) &&
424                         in_array('first_name', $displayColumns['NAME']['related_fields'])) {
425                                 $lvsParams['overrideLastNameOrder'] = true;
426                 }
427
428         if(!empty($this->displayTpl))
429         {
430                 //MFH BUG #14296
431             $where = '';
432             if(!empty($whereArray)){
433                 $where = '(' . implode(') AND (', $whereArray) . ')';
434             }
435             $this->lvs->setup($this->seedBean, $this->displayTpl, $where , $lvsParams, 0, $this->displayRows/*, $filterFields*/);
436             if(in_array('CREATED_BY', array_keys($displayColumns))) { // handle the created by field
437                 foreach($this->lvs->data['data'] as $row => $data) {
438                     $this->lvs->data['data'][$row]['CREATED_BY'] = get_assigned_user_name($data['CREATED_BY']);
439                 }
440             }
441             // assign a baseURL w/ the action set as DisplayDashlet
442             foreach($this->lvs->data['pageData']['urls'] as $type => $url) {
443                 // awu Replacing action=DisplayDashlet with action=DynamicAction&DynamicAction=DisplayDashlet
444                 if($type == 'orderBy')
445                     $this->lvs->data['pageData']['urls'][$type] = preg_replace('/(action=.*&)/Ui', 'action=DynamicAction&DynamicAction=displayDashlet&', $url);
446                 else
447                     $this->lvs->data['pageData']['urls'][$type] = preg_replace('/(action=.*&)/Ui', 'action=DynamicAction&DynamicAction=displayDashlet&', $url) . '&sugar_body_only=1&id=' . $this->id;
448             }
449
450             $this->lvs->ss->assign('dashletId', $this->id);
451         }
452     }
453
454    /**
455      * Displays the Dashlet, must call process() prior to calling this
456      *
457      * @return string HTML that displays Dashlet
458      */
459     function display() {
460         return parent::display() . $this->lvs->display(false) . $this->processAutoRefresh();
461     }
462
463     /**
464      * Filter the $_REQUEST and only save only the needed options
465      * @param array $req the array to pull options from
466      *
467      * @return array options array
468      */
469     function saveOptions($req) {
470         $options = array();
471
472                 $this->loadCustomMetadata();
473         foreach($req as $name => $value) {
474             if(!is_array($value)) $req[$name] = trim($value);
475         }
476         $options['filters'] = array();
477         foreach($this->searchFields as $name=>$params) {
478             $widgetDef = $this->seedBean->field_defs[$name];
479             //bug39170 - begin
480             if($widgetDef['name']=='created_by_name' && $req['created_by']) $widgetDef['name'] = 'created_by';
481             if($widgetDef['name']=='modified_by_name' && $req['modified_user_id']) $widgetDef['name'] = 'modified_user_id';
482             //bug39170 - end
483             if($widgetDef['type'] == 'datetimecombo' || $widgetDef['type'] == 'datetime' || $widgetDef['type'] == 'date') { // special case datetime types
484                 $options['filters'][$widgetDef['name']] = array();
485                 if(!empty($req['type_' . $widgetDef['name']])) { // save the type of date filter
486                     $options['filters'][$widgetDef['name']]['type'] = $req['type_' . $widgetDef['name']];
487                 }
488                 if(!empty($req['date_' . $widgetDef['name']])) { // save the date
489                     $options['filters'][$widgetDef['name']]['date'] = $req['date_' . $widgetDef['name']];
490                 }
491             }
492             elseif(!empty($req[$widgetDef['name']])) {
493                 $options['filters'][$widgetDef['name']] = $req[$widgetDef['name']];
494             }
495         }
496         if(!empty($req['dashletTitle'])) {
497             $options['title'] = $req['dashletTitle'];
498         }
499
500         // Don't save the options for myItemsOnly if we're not even showing the options.
501         if($this->showMyItemsOnly){
502             if(!empty($req['myItemsOnly'])) {
503                  $options['myItemsOnly'] = $req['myItemsOnly'];
504             }
505             else {
506                 $options['myItemsOnly'] = false;
507             }
508         }
509         $options['displayRows'] = empty($req['displayRows']) ? '5' : $req['displayRows'];
510         // displayColumns
511         if(!empty($req['displayColumnsDef'])) {
512             $options['displayColumns'] = explode('|', $req['displayColumnsDef']);
513         }
514         $options['autoRefresh'] = empty($req['autoRefresh']) ? '0' : $req['autoRefresh'];
515         return $options;
516     }
517
518     /**
519      * Internal function to add custom fields
520      *
521      */
522     function addCustomFields() {
523         foreach($this->seedBean->field_defs as $fieldName => $def) {
524             if(!empty($def['type']) && $def['type'] == 'html')
525                 continue;
526             if(isset($def['vname'])) {
527                 $translated = translate($def['vname'], $this->seedBean->module_dir);
528                 if(is_array($translated)) $translated = $def['vname'];
529                 if(!empty($def['source']) && $def['source'] == 'custom_fields') {
530                         if(isset($this->columns[$fieldName]['default']) && $this->columns[$fieldName]['default']){
531                                 $this->columns[$fieldName] = array('width' => '10',
532                                                        'label' => $translated,
533                                                        'default' => 1);
534                         }else{
535                     $this->columns[$fieldName] = array('width' => '10',
536                                                        'label' => $translated);
537                         }
538
539                 }
540             }
541         }
542     }
543 }
544 ?>