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.
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/ListView/ListViewSmarty.php');
40 require_once('include/TemplateHandler/TemplateHandler.php');
41 require_once('include/SearchForm/SearchForm2.php');
42 define("NUM_COLS", 2);
43 class PopupSmarty extends ListViewSmarty{
45 var $contextMenus = false;
47 var $mailmerge = false;
48 var $mergeduplicates = false;
49 var $quickViewLinks = false;
50 var $multiSelect = false;
60 var $searchdefs = array();
61 var $listviewdefs = array();
62 var $searchFields = array();
64 var $filter_fields = array();
68 var $massUpdateData = '';
70 function PopupSmarty($seed, $module){
71 parent::ListViewSmarty();
72 $this->th = new TemplateHandler();
73 $this->th->loadSmarty();
75 $this->view = 'Popup';
76 $this->module = $module;
77 $this->searchForm = new SearchForm($this->seed, $this->module);
78 $this->th->deleteTemplate($module, $this->view);
83 * Assign several arrow image attributes to TemplateHandler smarty. Such as width, height, etc.
87 function processArrowVars()
89 $pathParts = pathinfo(SugarThemeRegistry::current()->getImageURL('arrow.gif',false));
91 list($width,$height) = getimagesize($pathParts['dirname'].'/'.$pathParts['basename']);
93 $this->th->ss->assign('arrowExt', $pathParts['extension']);
94 $this->th->ss->assign('arrowWidth', $width);
95 $this->th->ss->assign('arrowHeight', $height);
96 $this->th->ss->assign('arrowAlt', translate('LBL_SORT'));
100 * Processes the request. Calls ListViewData process. Also assigns all lang strings, export links,
101 * This is called from ListViewDisplay
103 * @param file file Template file to use
104 * @param data array from ListViewData
105 * @param html_var string the corresponding html var in xtpl per row
108 function process($file, $data, $htmlVar) {
110 global $odd_bg, $even_bg, $hilite_bg, $click_bg, $app_strings;
111 parent::process($file, $data, $htmlVar);
117 foreach($this->displayColumns as $name => $params) {
118 $totalWidth += $params['width'];
120 $adjustment = $totalWidth / 100;
122 $contextMenuObjectsTypes = array();
123 foreach($this->displayColumns as $name => $params) {
124 $this->displayColumns[$name]['width'] = round($this->displayColumns[$name]['width'] / $adjustment, 2);
125 // figure out which contextMenu objectsTypes are required
126 if(!empty($params['contextMenu']['objectType']))
127 $contextMenuObjectsTypes[$params['contextMenu']['objectType']] = true;
129 $this->th->ss->assign('displayColumns', $this->displayColumns);
132 $this->th->ss->assign('bgHilite', $hilite_bg);
133 $this->th->ss->assign('colCount', count($this->displayColumns) + 1);
134 $this->th->ss->assign('htmlVar', strtoupper($htmlVar));
135 $this->th->ss->assign('moduleString', $this->moduleString);
136 $this->th->ss->assign('editLinkString', $GLOBALS['app_strings']['LBL_EDIT_BUTTON']);
137 $this->th->ss->assign('viewLinkString', $GLOBALS['app_strings']['LBL_VIEW_BUTTON']);
140 $this->searchForm->parsedView = 'popup_query_form';
141 $this->searchForm->displayType = 'popupView';
142 $this->th->ss->assign('searchForm', $this->searchForm->display(false));
145 if($this->overlib) $this->th->ss->assign('overlib', true);
146 if($this->export) $this->th->ss->assign('exportLink', $this->buildExportLink());
147 $this->th->ss->assign('quickViewLinks', $this->quickViewLinks);
148 if($this->mailMerge) $this->th->ss->assign('mergeLink', $this->buildMergeLink()); // still check for mailmerge access
149 if($this->mergeduplicates) $this->th->ss->assign('mergedupLink', $this->buildMergeDuplicatesLink());
152 if (!empty($_REQUEST['mode']) && strtoupper($_REQUEST['mode']) == 'MULTISELECT') {
153 $this->multiSelect = true;
155 // handle save checks and stuff
156 if($this->multiSelect) {
157 $this->th->ss->assign('selectedObjectsSpan', $this->buildSelectedObjectsSpan());
158 $this->th->ss->assign('multiSelectData', $this->getMultiSelectData());
159 $this->th->ss->assign('MODE', "<input type='hidden' name='mode' value='MultiSelect'>");
160 $pageTotal = $this->data['pageData']['offsets']['next'] - $this->data['pageData']['offsets']['current'];
161 if($this->data['pageData']['offsets']['next'] < 0){ // If we are on the last page, 'next' is -1, which means we have to have a custom calculation
162 $pageTotal = $this->data['pageData']['offsets']['total'] - $this->data['pageData']['offsets']['current'];
164 $this->th->ss->assign('selectLink', $this->buildSelectLink('select_link', $this->data['pageData']['offsets']['total'], $pageTotal));
167 $this->processArrows($data['pageData']['ordering']);
168 $this->th->ss->assign('prerow', $this->multiSelect);
169 $this->th->ss->assign('rowColor', array('oddListRow', 'evenListRow'));
170 $this->th->ss->assign('bgColor', array($odd_bg, $even_bg));
171 $this->th->ss->assign('contextMenus', $this->contextMenus);
174 if($this->contextMenus && !empty($contextMenuObjectsTypes)) {
176 $cm = new contextMenu();
177 foreach($contextMenuObjectsTypes as $type => $value) {
178 $cm->loadFromFile($type);
179 $script .= $cm->getScript();
180 $cm->menuItems = array(); // clear menuItems out
182 $this->th->ss->assign('contextMenuScript', $script);
186 $this->_build_field_defs();
188 // arrow image attributes
189 $this->processArrowVars();
193 * Display the Smarty template. Here we are using the TemplateHandler for caching per the module.
195 function display($end = true) {
198 if(!is_file(sugar_cached("jsLanguage/{$GLOBALS['current_language']}.js"))) {
199 require_once('include/language/jsLanguage.php');
200 jsLanguage::createAppStringsCache($GLOBALS['current_language']);
202 $jsLang = getVersionedScript("cache/jsLanguage/{$GLOBALS['current_language']}.js", $GLOBALS['sugar_config']['js_lang_version']);
204 $this->th->ss->assign('data', $this->data['data']);
205 $this->data['pageData']['offsets']['lastOffsetOnPage'] = $this->data['pageData']['offsets']['current'] + count($this->data['data']);
206 $this->th->ss->assign('pageData', $this->data['pageData']);
208 $navStrings = array('next' => $GLOBALS['app_strings']['LNK_LIST_NEXT'],
209 'previous' => $GLOBALS['app_strings']['LNK_LIST_PREVIOUS'],
210 'end' => $GLOBALS['app_strings']['LNK_LIST_END'],
211 'start' => $GLOBALS['app_strings']['LNK_LIST_START'],
212 'of' => $GLOBALS['app_strings']['LBL_LIST_OF']);
213 $this->th->ss->assign('navStrings', $navStrings);
216 $associated_row_data = array();
218 //C.L. - Bug 44324 - Override the NAME entry to not display salutation so that the data returned from the popup can be searched on correctly
219 $searchNameOverride = !empty($this->seed) && $this->seed instanceof Person && (isset($this->data['data'][0]['FIRST_NAME']) && isset($this->data['data'][0]['LAST_NAME'])) ? true : false;
222 foreach($this->data['data'] as $val)
224 $associated_row_data[$val['ID']] = $val;
225 if($searchNameOverride)
227 $associated_row_data[$val['ID']]['NAME'] = $locale->getLocaleFormattedName($val['FIRST_NAME'], $val['LAST_NAME']);
230 $is_show_fullname = showFullName() ? 1 : 0;
231 $json = getJSONobj();
232 $this->th->ss->assign('jsLang', $jsLang);
233 $this->th->ss->assign('lang', substr($GLOBALS['current_language'], 0, 2));
234 $this->th->ss->assign('headerTpl', 'include/Popups/tpls/header.tpl');
235 $this->th->ss->assign('footerTpl', 'include/Popups/tpls/footer.tpl');
236 $this->th->ss->assign('ASSOCIATED_JAVASCRIPT_DATA', 'var associated_javascript_data = '.$json->encode($associated_row_data). '; var is_show_fullname = '.$is_show_fullname.';');
237 $this->th->ss->assign('module', $this->seed->module_dir);
238 $request_data = empty($_REQUEST['request_data']) ? '' : $_REQUEST['request_data'];
239 $this->th->ss->assign('request_data', $request_data);
240 $this->th->ss->assign('fields', $this->fieldDefs);
241 $this->th->ss->assign('formData', $this->formData);
242 $this->th->ss->assign('APP', $GLOBALS['app_strings']);
243 $this->th->ss->assign('MOD', $GLOBALS['mod_strings']);
244 $this->th->ss->assign('popupMeta', $this->_popupMeta);
245 $this->th->ss->assign('current_query', base64_encode(serialize($_REQUEST)));
246 $this->th->ss->assign('customFields', $this->customFieldDefs);
247 $this->th->ss->assign('numCols', NUM_COLS);
248 $this->th->ss->assign('massUpdateData', $this->massUpdateData);
249 $this->th->ss->assign('sugarVersion', $GLOBALS['sugar_version']);
250 $this->th->ss->assign('should_process', $this->should_process);
253 $this->th->ss->assign('ADDFORM', $this->getQuickCreate());//$this->_getAddForm());
254 $this->th->ss->assign('ADDFORMHEADER', $this->_getAddFormHeader());
255 $this->th->ss->assign('object_name', $this->seed->object_name);
257 $this->th->ss->assign('LIST_HEADER', get_form_header($GLOBALS['mod_strings']['LBL_LIST_FORM_TITLE'], '', false));
258 $this->th->ss->assign('SEARCH_FORM_HEADER', get_form_header($GLOBALS['mod_strings']['LBL_SEARCH_FORM_TITLE'], '', false));
259 $str = $this->th->displayTemplate($this->seed->module_dir, $this->view, $this->tpl);
264 * Setup up the smarty template. we added an extra step here to add the order by from the popupdefs.
266 function setup($file) {
268 if(isset($this->_popupMeta)){
269 if(isset($this->_popupMeta['create']['formBase'])) {
270 require_once('modules/' . $this->seed->module_dir . '/' . $this->_popupMeta['create']['formBase']);
271 $this->_create = true;
274 if(!empty($this->_popupMeta['create'])){
275 $formBase = new $this->_popupMeta['create']['formBaseClass']();
276 if(isset($_REQUEST['doAction']) && $_REQUEST['doAction'] == 'save')
278 //If it's a new record, set useRequired to false
279 $useRequired = empty($_REQUEST['id']) ? false : true;
280 $formBase->handleSave('', false, $useRequired);
285 if(!empty($this->_popupMeta['orderBy'])){
286 $params['orderBy'] = $this->_popupMeta['orderBy'];
289 if(file_exists('custom/modules/'.$this->module.'/metadata/metafiles.php')){
290 require('custom/modules/'.$this->module.'/metadata/metafiles.php');
291 }elseif(file_exists('modules/'.$this->module.'/metadata/metafiles.php')){
292 require('modules/'.$this->module.'/metadata/metafiles.php');
295 if(!empty($metafiles[$this->module]['searchfields'])) {
296 require($metafiles[$this->module]['searchfields']);
297 } elseif(file_exists('modules/'.$this->module.'/metadata/SearchFields.php')) {
298 require('modules/'.$this->module.'/metadata/SearchFields.php');
300 $this->searchdefs[$this->module]['templateMeta']['maxColumns'] = 2;
301 $this->searchdefs[$this->module]['templateMeta']['widths']['label'] = 10;
302 $this->searchdefs[$this->module]['templateMeta']['widths']['field'] = 30;
304 $this->searchForm->view = 'PopupSearchForm';
305 $this->searchForm->setup($this->searchdefs, $searchFields, 'include/SearchForm/tpls/SearchFormGenericAdvanced.tpl', 'advanced_search', $this->listviewdefs);
307 $lv = new ListViewSmarty();
308 $displayColumns = array();
309 if(!empty($_REQUEST['displayColumns'])) {
310 foreach(explode('|', $_REQUEST['displayColumns']) as $num => $col) {
311 if(!empty($listViewDefs[$this->module][$col]))
312 $displayColumns[$col] = $this->listviewdefs[$this->module][$col];
316 foreach($this->listviewdefs[$this->module] as $col => $para) {
317 if(!empty($para['default']) && $para['default'])
318 $displayColumns[$col] = $para;
321 $params['massupdate'] = true;
322 if(!empty($_REQUEST['orderBy'])) {
323 $params['orderBy'] = $_REQUEST['orderBy'];
324 $params['overrideOrder'] = true;
325 if(!empty($_REQUEST['sortOrder'])) $params['sortOrder'] = $_REQUEST['sortOrder'];
328 $lv->displayColumns = $displayColumns;
329 $this->searchForm->lv = $lv;
330 $this->searchForm->displaySavedSearch = false;
333 $this->searchForm->populateFromRequest('advanced_search');
334 $searchWhere = $this->_get_where_clause();
335 $this->searchColumns = $this->searchForm->searchColumns;
336 //parent::setup($this->seed, $file, $searchWhere, $params, 0, -1, $this->filter_fields);
338 $this->should_process = true;
340 if(isset($params['export'])) {
341 $this->export = $params['export'];
343 if(!empty($params['multiSelectPopup'])) {
344 $this->multi_select_popup = $params['multiSelectPopup'];
346 if(!empty($params['massupdate']) && $params['massupdate'] != false) {
347 $this->show_mass_update_form = true;
348 $this->mass = new MassUpdate();
349 $this->mass->setSugarBean($this->seed);
350 if(!empty($params['handleMassupdate']) || !isset($params['handleMassupdate'])) {
351 $this->mass->handleMassUpdate();
355 // create filter fields based off of display columns
356 if(empty($this->filter_fields) || $this->mergeDisplayColumns) {
357 foreach($this->displayColumns as $columnName => $def) {
358 $this->filter_fields[strtolower($columnName)] = true;
359 if(!empty($def['related_fields'])) {
360 foreach($def['related_fields'] as $field) {
361 //id column is added by query construction function. This addition creates duplicates
362 //and causes issues in oracle. #10165
363 if ($field != 'id') {
364 $this->filter_fields[$field] = true;
368 if (!empty($this->seed->field_defs[strtolower($columnName)]['db_concat_fields'])) {
369 foreach($this->seed->field_defs[strtolower($columnName)]['db_concat_fields'] as $index=>$field){
370 if(!isset($this->filter_fields[strtolower($field)]) || !$this->filter_fields[strtolower($field)])
372 $this->filter_fields[strtolower($field)] = true;
377 foreach ($this->searchColumns as $columnName => $def )
379 $this->filter_fields[strtolower($columnName)] = true;
384 if (!empty($_REQUEST['query']) || (!empty($GLOBALS['sugar_config']['save_query']) && $GLOBALS['sugar_config']['save_query'] != 'populate_only')) {
385 $data = $this->lvd->getListViewData($this->seed, $searchWhere, 0, -1, $this->filter_fields, $params, 'id');
387 $this->should_process = false;
391 'bean'=>array('moduleDir'=>$this->seed->module_dir),
393 'offsets'=>array('total'=>0,'next'=>0,'current'=>0),
398 foreach($this->displayColumns as $columnName => $def)
400 $seedName = strtolower($columnName);
402 if(empty($this->displayColumns[$columnName]['type'])){
403 if(!empty($this->lvd->seed->field_defs[$seedName]['type'])){
404 $seedDef = $this->lvd->seed->field_defs[$seedName];
405 $this->displayColumns[$columnName]['type'] = (!empty($seedDef['custom_type']))?$seedDef['custom_type']:$seedDef['type'];
407 $this->displayColumns[$columnName]['type'] = '';
411 if(!empty($this->lvd->seed->field_defs[$seedName]['options'])){
412 $this->displayColumns[$columnName]['options'] = $this->lvd->seed->field_defs[$seedName]['options'];
416 if($this->displayColumns[$columnName]['type'] == 'html') {
417 $cField = $this->seed->custom_fields;
418 if(isset($cField) && isset($cField->bean->$seedName)) {
419 $seedName2 = strtoupper($columnName);
420 $htmlDisplay = html_entity_decode($cField->bean->$seedName);
422 while($count < count($data['data'])) {
423 $data['data'][$count][$seedName2] = &$htmlDisplay;
429 if (!empty($this->lvd->seed->field_defs[$seedName]['sort_on'])) {
430 $this->displayColumns[$columnName]['orderBy'] = $this->lvd->seed->field_defs[$seedName]['sort_on'];
434 $this->process($file, $data, $this->seed->object_name);
438 * Return the where clause as per the REQUEST.
440 function _get_where_clause()
443 $where_clauses = $this->searchForm->generateSearchWhere(true, $this->seed->module_dir);
445 // Bug 43452 - FG - Changed the way generated Where array is imploded into the string.
446 // Now it's imploding in the same way view.list.php do.
447 if (count($where_clauses) > 0 ) {
448 $where = '( ' . implode(' and ', $where_clauses) . ' )';
451 // Need to include the default whereStatement
452 if(!empty($this->_popupMeta['whereStatement'])){
453 if(!empty($where))$where .= ' AND ';
454 $where .= $this->_popupMeta['whereStatement'];
461 * Generate the data for the search form on the header of the Popup.
463 function _build_field_defs(){
464 $this->formData = array();
465 $this->customFieldDefs = array();
466 foreach($this->searchdefs[$this->module]['layout']['advanced_search'] as $data){
469 $this->formData[] = array('field' => $data);
471 $this->customFieldDefs[$data['name']]= $data;
472 if(!empty($_REQUEST[$data['name']]))
473 $value = $_REQUEST[$data['name']];
474 $this->customFieldDefs[$data['name']]['value'] = $value;
476 $this->formData[] = array('field' => array('name'=>$data));
478 $this->fieldDefs = array();
480 $this->seed->fill_in_additional_detail_fields();
482 foreach($this->seed->toArray() as $name => $value) {
483 $this->fieldDefs[$name] = $this->seed->field_defs[$name];
484 //if we have a relate type then reset to name so that we end up with a textbox
485 //rather than a select button
486 $this->fieldDefs[$name]['name'] = $this->fieldDefs[$name]['name'];
487 if($this->fieldDefs[$name]['type'] == 'relate')
488 $this->fieldDefs[$name]['type'] = 'name';
489 if(isset($this->fieldDefs[$name]['options']) && isset($GLOBALS['app_list_strings'][$this->fieldDefs[$name]['options']])) {
490 $this->fieldDefs[$name]['options'] = $GLOBALS['app_list_strings'][$this->fieldDefs[$name]['options']]; // fill in enums
492 if(!empty($_REQUEST[$name]))
493 $value = $_REQUEST[$name];
494 $this->fieldDefs[$name]['value'] = $value;
499 function _getAddForm(){
501 if(!$this->seed->ACLAccess('save')){
504 if(!empty($this->_popupMeta['create'])){
505 $formBase = new $this->_popupMeta['create']['formBaseClass']();
509 // TODO: cleanup the construction of $addform
510 $prefix = empty($this->_popupMeta['create']['getFormBodyParams'][0]) ? '' : $this->_popupMeta['create']['getFormBodyParams'][0];
511 $mod = empty($this->_popupMeta['create']['getFormBodyParams'][1]) ? '' : $this->_popupMeta['create']['getFormBodyParams'][1];
512 $formBody = empty($this->_popupMeta['create']['getFormBodyParams'][2]) ? '' : $this->_popupMeta['create']['getFormBodyParams'][2];
514 $getFormMethod = (empty($this->_popupMeta['create']['getFormMethod']) ? 'getFormBody' : $this->_popupMeta['create']['getFormMethod']);
515 $formbody = $formBase->$getFormMethod($prefix, $mod, $formBody);
517 $addform = '<table><tr><td nowrap="nowrap" valign="top">'
518 . str_replace('<br>', '</td><td nowrap="nowrap" valign="top"> ', $formbody)
519 . '</td></tr></table>'
520 . '<input type="hidden" name="action" value="Popup" />';
526 function _getAddFormHeader(){
527 $lbl_save_button_title = $GLOBALS['app_strings']['LBL_SAVE_BUTTON_TITLE'];
528 $lbl_save_button_key = $GLOBALS['app_strings']['LBL_SAVE_BUTTON_KEY'];
529 $lbl_save_button_label = $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'];
530 $module_dir = $this->seed->module_dir;
532 <input type="hidden" name="create" value="true">
533 <input type="hidden" name="popup" value="true">
534 <input type="hidden" name="to_pdf" value="true">
535 <input type="hidden" name="return_module" value="$module_dir">
536 <input type="hidden" name="return_action" value="Popup">
538 // if metadata contains custom inputs for the quickcreate
539 if(!empty($this->_popupMeta['customInput']) && is_array($this->_popupMeta['customInput'])) {
540 foreach($this->_popupMeta['customInput'] as $key => $value)
541 $formSave .= '<input type="hidden" name="' . $key . '" value="'. $value .'">\n';
545 $addformheader = get_form_header($this->_popupMeta['create']['createButton'], $formSave, false);
546 return $addformheader;
549 function getQuickCreate(){
550 require_once("include/EditView/PopupQuickCreate.php");
551 $qc = new PopupQuickCreate($this->module);
552 return $qc->process($this->module);