2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 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 ********************************************************************************/
38 require_once('include/Dashlets/Dashlet.php');
39 require_once('include/ListView/ListViewSmarty.php');
40 require_once('include/generic/LayoutManager.php');
42 class DashletGeneric extends Dashlet {
44 * Fields that are searchable
49 * Displayable columns (ones available to display)
54 * Bean file used in this Dashlet
59 * collection of filters to apply
64 * Number of Rows to display
67 var $displayRows = '5';
69 * Actual columns to display, will be a subset of $columns
72 var $displayColumns = null;
74 * Flag to display only the current users's items.
77 var $myItemsOnly = true;
79 * Flag to display "myItemsOnly" checkbox in the DashletGenericConfigure.
82 var $showMyItemsOnly = true;
84 * location of Smarty template file for display
87 var $displayTpl = 'include/Dashlets/DashletGenericDisplay.tpl';
89 * location of smarty template file for configuring
92 var $configureTpl = 'include/Dashlets/DashletGenericConfigure.tpl';
94 * smarty object for the generic configuration template
98 /** search inputs to be populated in configure template.
99 * modify this after processDisplayOptions, but before displayOptions to modify search inputs
102 var $currentSearchFields;
104 * ListView Smarty Class
110 function DashletGeneric($id, $options = null) {
111 parent::Dashlet($id);
112 $this->isConfigurable = true;
113 if(isset($options)) {
114 if(!empty($options['filters'])) $this->filters = $options['filters'];
115 if(!empty($options['title'])) $this->title = $options['title'];
116 if(!empty($options['displayRows'])) $this->displayRows = $options['displayRows'];
117 if(!empty($options['displayColumns'])) $this->displayColumns = $options['displayColumns'];
118 if(isset($options['myItemsOnly'])) $this->myItemsOnly = $options['myItemsOnly'];
121 $this->layoutManager = new LayoutManager();
122 $this->layoutManager->setAttribute('context', 'Report');
123 // fake a reporter object here just to pass along the db type used in many widgets.
124 // this should be taken out when sugarwidgets change
125 $temp = (object) array('db' => &$GLOBALS['db'], 'report_def_str' => '');
126 $this->layoutManager->setAttributePtr('reporter', $temp);
127 $this->lvs = new ListViewSmarty();
131 * Sets up the display options template
133 * @return string HTML that shows options
135 function processDisplayOptions() {
136 require_once('include/templates/TemplateGroupChooser.php');
138 $this->configureSS = new Sugar_Smarty();
140 $chooser = new TemplateGroupChooser();
142 $chooser->args['id'] = 'edit_tabs';
143 $chooser->args['left_size'] = 5;
144 $chooser->args['right_size'] = 5;
145 $chooser->args['values_array'][0] = array();
146 $chooser->args['values_array'][1] = array();
148 $this->loadCustomMetadata();
149 $this->addCustomFields();
150 if($this->displayColumns) {
151 // columns to display
152 foreach($this->displayColumns as $num => $name) {
153 // defensive code for array being returned
154 $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir);
155 if(is_array($translated)) $translated = $this->columns[$name]['label'];
156 $chooser->args['values_array'][0][$name] = trim($translated, ':');
158 // columns not displayed
159 foreach(array_diff(array_keys($this->columns), array_values($this->displayColumns)) as $num => $name) {
160 // defensive code for array being returned
161 $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir);
162 if(is_array($translated)) $translated = $this->columns[$name]['label'];
163 $chooser->args['values_array'][1][$name] = trim($translated, ':');
167 foreach($this->columns as $name => $val) {
168 // defensive code for array being returned
169 $translated = translate($this->columns[$name]['label'], $this->seedBean->module_dir);
170 if(is_array($translated)) $translated = $this->columns[$name]['label'];
171 if(!empty($val['default']) && $val['default'])
172 $chooser->args['values_array'][0][$name] = trim($translated, ':');
174 $chooser->args['values_array'][1][$name] = trim($translated, ':');
178 $chooser->args['left_name'] = 'display_tabs';
179 $chooser->args['right_name'] = 'hide_tabs';
180 $chooser->args['max_left'] = '6';
182 $chooser->args['left_label'] = $GLOBALS['app_strings']['LBL_DISPLAY_COLUMNS'];
183 $chooser->args['right_label'] = $GLOBALS['app_strings']['LBL_HIDE_COLUMNS'];
184 $chooser->args['title'] = '';
185 $this->configureSS->assign('columnChooser', $chooser->display());
190 if(!is_array($this->filters)) {
191 // use default search params
192 $this->filters = array();
193 foreach($this->searchFields as $name => $params) {
194 if(!empty($params['default']))
195 $this->filters[$name] = $params['default'];
198 foreach($this->searchFields as $name=>$params) {
200 $name = strtolower($name);
201 $currentSearchFields[$name] = array();
202 $widgetDef = $this->seedBean->field_defs[$name];
203 if($widgetDef['type'] == 'enum') $widgetDef['remove_blank'] = true; // remove the blank option for the dropdown
204 if($widgetDef['name'] == 'assigned_user_name') $widgetDef['name'] = 'assigned_user_id';
205 $widgetDef['input_name0'] = empty($this->filters[$name]) ? '' : $this->filters[$name];
206 $currentSearchFields[$name]['label'] = !empty($params['label']) ? translate($params['label'], $this->seedBean->module_dir) : translate($widgetDef['vname'], $this->seedBean->module_dir);
207 $currentSearchFields[$name]['input'] = $this->layoutManager->widgetDisplayInput($widgetDef, true, (empty($this->filters[$name]) ? '' : $this->filters[$name]));
209 else { // ability to create spacers in input fields
210 $currentSearchFields['blank' + $count]['label'] = '';
211 $currentSearchFields['blank' + $count]['input'] = '';
215 $this->currentSearchFields = $currentSearchFields;
217 $this->configureSS->assign('strings', array('general' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_GENERAL'],
218 'filters' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_FILTERS'],
219 'myItems' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY'],
220 'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'],
221 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'],
222 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL']));
223 $this->configureSS->assign('id', $this->id);
224 $this->configureSS->assign('showMyItemsOnly', $this->showMyItemsOnly);
225 $this->configureSS->assign('myItemsOnly', $this->myItemsOnly);
226 $this->configureSS->assign('searchFields', $this->currentSearchFields);
228 $this->configureSS->assign('dashletTitle', $this->title);
231 $displayRowOptions = $GLOBALS['sugar_config']['dashlet_display_row_options'];
232 $this->configureSS->assign('displayRowOptions', $displayRowOptions);
233 $this->configureSS->assign('displayRowSelect', $this->displayRows);
236 * Displays the options for this Dashlet
238 * @return string HTML that shows options
240 function displayOptions() {
241 $this->processDisplayOptions();
242 return parent::displayOptions() . $this->configureSS->fetch($this->configureTpl);
245 function buildWhere() {
246 global $current_user;
248 $returnArray = array();
250 if(!is_array($this->filters)) {
252 $this->filters = array();
253 foreach($this->searchFields as $name => $params) {
254 if(!empty($params['default']))
255 $this->filters[$name] = $params['default'];
258 foreach($this->filters as $name=>$params) {
259 if(!empty($params)) {
260 if($name == 'assigned_user_id' && $this->myItemsOnly) continue; // don't handle assigned user filter if filtering my items only
261 $widgetDef = $this->seedBean->field_defs[$name];
263 $widgetClass = $this->layoutManager->getClassFromWidgetDef($widgetDef, true);
264 $widgetDef['table'] = $this->seedBean->table_name;
265 $widgetDef['table_alias'] = $this->seedBean->table_name;
266 if(!empty($widgetDef['source']) && $widgetDef['source'] == 'custom_fields'){
267 $widgetDef['table'] = $this->seedBean->table_name."_cstm";
268 $widgetDef['table_alias'] = $widgetDef['table'];
270 switch($widgetDef['type']) {// handle different types
273 case 'datetimecombo':
274 if(is_array($params) && !empty($params)) {
275 if(!empty($params['date']))
276 $widgetDef['input_name0'] = $params['date'];
277 $filter = 'queryFilter' . $params['type'];
280 $filter = 'queryFilter' . $params;
282 array_push($returnArray, $widgetClass->$filter($widgetDef, true));
284 case 'assigned_user_name':
285 // This type runs through the SugarWidgetFieldname class, and needs a little extra help to make it through
286 if ( ! isset($widgetDef['column_key']) ) {
287 $widgetDef['column_key'] = $name;
289 // No break here, we want to run through the default handler
291 $widgetDef['input_name0'] = $params;
292 if(is_array($params) && !empty($params)) { // handle array query
293 array_push($returnArray, $widgetClass->queryFilterone_of($widgetDef, false));
296 array_push($returnArray, $widgetClass->queryFilterStarts_With($widgetDef, true));
298 $widgetDef['input_name0'] = $params;
304 if($this->myItemsOnly) array_push($returnArray, $this->seedBean->table_name . '.' . "assigned_user_id = '" . $current_user->id . "'");
309 protected function loadCustomMetadata()
311 $customMetadate = 'custom/modules/'.$this->seedBean->module_dir.'/metadata/dashletviewdefs.php';
312 if ( file_exists ( $customMetadate )){
313 require($customMetadate);
314 $this->searchFields = $dashletData[$this->seedBean->module_dir.'Dashlet']['searchFields'];
315 foreach($this->searchFields as $key =>$def){
316 if($key == 'assigned_user_name'){
317 $this->searchFields['assigned_user_id'] = $def;
318 unset($this->searchFields['assigned_user_name'] );
323 $this->columns = $dashletData[$this->seedBean->module_dir.'Dashlet']['columns'];
328 * Does all dashlet processing, here's your chance to modify the rows being displayed!
330 function process($lvsParams = array()) {
331 $currentSearchFields = array();
332 $configureView = true; // configure view or regular view
334 $whereArray = array();
335 $lvsParams['massupdate'] = false;
337 $this->loadCustomMetadata();
338 $this->addCustomFields();
340 if(isset($this->filters) || $this->myItemsOnly) {
341 $whereArray = $this->buildWhere();
344 $this->lvs->export = false;
345 $this->lvs->multiSelect = false;
347 $displayColumns = array();
348 if(!empty($this->displayColumns)) { // use user specified columns
349 foreach($this->displayColumns as $name => $val) {
350 $displayColumns[strtoupper($val)] = $this->columns[$val];
351 $displayColumns[strtoupper($val)]['label'] = trim($displayColumns[strtoupper($val)]['label'], ':');// strip : at the end of headers
354 else if (isset($this->columns)){
356 foreach($this->columns as $name => $val) {
357 if(!empty($val['default']) && $val['default']) {
358 $displayColumns[strtoupper($name)] = $val;
359 $displayColumns[strtoupper($name)]['label'] = trim($displayColumns[strtoupper($name)]['label'], ':');
363 $this->lvs->displayColumns = $displayColumns;
365 $this->lvs->lvd->setVariableName($this->seedBean->object_name, array());
366 $lvdOrderBy = $this->lvs->lvd->getOrderBy(); // has this list been ordered, if not use default
367 if(!empty($lvsParams['orderBy']) && !empty($lvsParams['sortOrder'])){
368 $lvsParams['overrideOrder'] = true;
370 else if(empty($lvdOrderBy['orderBy'])) {
371 foreach($displayColumns as $colName => $colParams) {
372 if(!empty($colParams['defaultOrderColumn'])) {
373 $lvsParams['overrideOrder'] = true;
374 $lvsParams['orderBy'] = $colName;
375 $lvsParams['sortOrder'] = $colParams['defaultOrderColumn']['sortOrder'];
381 if(!empty($this->displayTpl))
385 if(!empty($whereArray)){
386 $where = '(' . implode(') AND (', $whereArray) . ')';
388 $this->lvs->setup($this->seedBean, $this->displayTpl, $where , $lvsParams, 0, $this->displayRows/*, $filterFields*/);
389 if(in_array('CREATED_BY', array_keys($displayColumns))) { // handle the created by field
390 foreach($this->lvs->data['data'] as $row => $data) {
391 $this->lvs->data['data'][$row]['CREATED_BY'] = get_assigned_user_name($data['CREATED_BY']);
394 // assign a baseURL w/ the action set as DisplayDashlet
395 foreach($this->lvs->data['pageData']['urls'] as $type => $url) {
396 // awu Replacing action=DisplayDashlet with action=DynamicAction&DynamicAction=DisplayDashlet
397 if($type == 'orderBy')
398 $this->lvs->data['pageData']['urls'][$type] = preg_replace('/(action=.*&)/Ui', 'action=DynamicAction&DynamicAction=displayDashlet&', $url);
400 $this->lvs->data['pageData']['urls'][$type] = preg_replace('/(action=.*&)/Ui', 'action=DynamicAction&DynamicAction=displayDashlet&', $url) . '&sugar_body_only=1&id=' . $this->id;
403 $this->lvs->ss->assign('dashletId', $this->id);
409 * Displays the Dashlet, must call process() prior to calling this
411 * @return string HTML that displays Dashlet
414 return parent::display() . $this->lvs->display(false);
418 * Filter the $_REQUEST and only save only the needed options
419 * @param array $req the array to pull options from
421 * @return array options array
423 function saveOptions($req) {
426 $this->loadCustomMetadata();
427 foreach($req as $name => $value) {
428 if(!is_array($value)) $req[$name] = trim($value);
430 $options['filters'] = array();
431 foreach($this->searchFields as $name=>$params) {
432 $widgetDef = $this->seedBean->field_defs[$name];
433 if($widgetDef['type'] == 'datetimecombo' || $widgetDef['type'] == 'datetime' || $widgetDef['type'] == 'date') { // special case datetime types
434 $options['filters'][$widgetDef['name']] = array();
435 if(!empty($req['type_' . $widgetDef['name']])) { // save the type of date filter
436 $options['filters'][$widgetDef['name']]['type'] = $req['type_' . $widgetDef['name']];
438 if(!empty($req['date_' . $widgetDef['name']])) { // save the date
439 $options['filters'][$widgetDef['name']]['date'] = $req['date_' . $widgetDef['name']];
442 elseif(!empty($req[$widgetDef['name']])) {
443 $options['filters'][$widgetDef['name']] = $req[$widgetDef['name']];
446 if(!empty($req['dashletTitle'])) {
447 $options['title'] = $req['dashletTitle'];
450 if(!empty($req['myItemsOnly'])) {
451 $options['myItemsOnly'] = $req['myItemsOnly'];
454 $options['myItemsOnly'] = false;
456 $options['displayRows'] = empty($req['displayRows']) ? '5' : $req['displayRows'];
458 if(!empty($req['displayColumnsDef'])) {
459 $options['displayColumns'] = explode('|', $req['displayColumnsDef']);
465 * Internal function to add custom fields
468 function addCustomFields() {
469 foreach($this->seedBean->field_defs as $fieldName => $def) {
470 if(!empty($def['type']) && $def['type'] == 'html')
472 if(isset($def['vname'])) {
473 $translated = translate($def['vname'], $this->seedBean->module_dir);
474 if(is_array($translated)) $translated = $def['vname'];
475 if(!empty($def['source']) && $def['source'] == 'custom_fields') {
476 if(isset($this->columns[$fieldName]['default']) && $this->columns[$fieldName]['default']){
477 $this->columns[$fieldName] = array('width' => '10',
478 'label' => $translated,
481 $this->columns[$fieldName] = array('width' => '10',
482 'label' => $translated);