2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
40 * DetailView - display single record
43 class DetailView extends ListView {
45 var $list_row_count = null;
46 var $return_to_list_only=false;
47 var $offset_key_mismatch=false;
48 var $no_record_found=false;
50 function DetailView(){
53 global $theme, $app_strings, $currentModule;
54 $this->local_theme = $theme;
55 $this->local_app_strings =$app_strings;
58 function processSugarBean($html_varName, $seed, &$offset, $isfirstview=0) {
59 global $row_count, $sugar_config;
62 global $previous_offset;
63 global $list_view_row_count;
64 global $current_offset;
65 if (!empty($sugar_config['disable_vcr']) ) {
66 $seed->retrieve($_REQUEST['record']);
71 $nav_history_set=false;
72 $nav_history_array=array();
74 $nav_ids_visited=array();
77 //get the session variable DETAIL_NAV_HISTORY,
78 //the format of the variable stamp,offset, array of IDs visited.
79 $nav_history=$this->getLocalSessionVariable($html_varName, "DETAIL_NAV_HISTORY");
80 if (!empty($nav_history)) {
81 $nav_history_set=true;
82 $nav_history_array=explode(":",$nav_history);
83 $nav_stamp=$nav_history_array[0];
84 $nav_offset=$nav_history_array[1];
85 eval("\$nav_ids_visited= ".$nav_history_array[2].";");
88 //from list offset is there but $bNavHistorySet is false.
89 //from next,previous,start and end buttons offset and $bNavHistorySet is true.
90 //from tracker offset is not there but $bNavHistorySet may or may not exist.
91 if (isset($_REQUEST['offset']) && !empty($_REQUEST['offset'])) {
93 $offset = $_REQUEST['offset'];
97 //if the stamp has changed, ignore the offset and navigate to the record.
98 //use case, search, navigate to detail, copy URL, search again, paste URL.
99 if (!$this->isRequestFromListView($html_varName)) {
100 $result = $seed->retrieve($_REQUEST['record']);
104 if ($nav_history_set) {
105 if (isset($nav_ids_visited[$offset])) {
106 unset($nav_ids_visited[$offset]);
111 if ($nav_history_set) {
112 //try to locate the ID in the nav_history array.
114 $key = array_search($_REQUEST['record'], $nav_ids_visited);
115 if ($key === false) {
116 //do not show the VCR buttons.
118 $result = $seed->retrieve($_REQUEST['record']);
122 $_REQUEST['offset'] = $offset;
123 $_GET['offset'] = $offset;
124 $_POST['offset'] = $offset;
126 $_REQUEST['stamp'] = $nav_stamp;
127 $_GET['stamp'] = $nav_stamp;
128 $_POST['stamp'] = $nav_stamp;
129 if (isset($nav_ids_visited[$offset])) {
130 unset($nav_ids_visited[$offset]);
134 if(!empty($seed->id))return $seed;
136 $result = $seed->retrieve($_REQUEST['record']);
141 //Check if this is the first time we have viewed this record
142 $var = $this->getLocalSessionVariable($html_varName, "IS_FIRST_VIEW");
143 if(!isset($var) || !$var){
147 $isFirstView = false;
149 //indicate that this is not the first time anymore
150 $this->setLocalSessionVariable($html_varName, "IS_FIRST_VIEW", false);
152 // All 3 databases require this because the limit query does a > db_offset comparision.
153 $db_offset=$offset-1;
155 $this->populateQueryWhere($isFirstView, $html_varName);
156 if(ACLController::requireOwner($seed->module_dir, 'view')) {
157 global $current_user;
158 $seed->getOwnerWhere($current_user->id);
159 if(!empty($this->query_where)) {
160 $this->query_where .= ' AND ';
162 $this->query_where .= $seed->getOwnerWhere($current_user->id);
165 $order = $this->getLocalSessionVariable($seed->module_dir.'2_'.$html_varName, "ORDER_BY");
167 if(!empty($order['orderBy']))
168 $orderBy = $order['orderBy'];
169 if(!empty($orderBy) && !empty($order['direction']))
170 $orderBy .= ' ' . $order['direction'];
172 $this->query_orderby = $seed->process_order_by($orderBy,null);
173 $current_offset = $_REQUEST['offset'] -1;
174 $response = $seed->process_detail_query(SugarVCR::retrieve($seed->module_dir), 0, -1, -1, '', $current_offset);
175 //$response = $seed->get_detail(, $this->query_where, $db_offset);
176 $object = $response['bean'];
177 $row_count = $response['row_count'];
178 $next_offset = $response['next_offset'];
179 $previous_offset = $response['previous_offset'];
180 $list_view_row_count = $row_count;
181 $this->setListViewRowCount($row_count);
183 //if the retrieved id is not same as the request ID then hide the VCR buttons.
184 if (empty($object->id)) {
185 $this->no_record_found=true;
187 if (empty($_REQUEST['InDetailNav']) and strcmp($_REQUEST['record'],$object->id)!=0) {
188 $this->offset_key_mismatch=true;
190 if ($this->no_record_found or $this->offset_key_mismatch ) {
191 if ($nav_history_set) {
192 $this->return_to_list_only=true;
194 $result = $seed->retrieve($_REQUEST['record']);
198 //update the request with correct value for the record attribute.
199 //need only when using the VCR buttuoms. This is a workaround need to fix the values
200 //set in the VCR links.
201 $_REQUEST['record'] = $object->id;
202 $_GET['record'] = $object->id;
203 $_POST['record'] = $object->id;
206 if (empty($nav_stamp)) {
207 $nav_stamp=$_GET['stamp'];
209 if (empty($nav_offset)) {
212 //store a maximum of 20 entries in the nav_ids_visited array.
213 //remove the oldest entry when this limit is reached.
214 if (count($nav_ids_visited) >= 20) {
215 reset($nav_ids_visited);
216 unset($nav_ids_visited[key($nav_ids_visited)]);
218 $nav_ids_visited[$offset]=$object->id;
219 $nav_history=sprintf("%s:%s:%s",$nav_stamp,$nav_offset,var_export($nav_ids_visited,true));
220 $this->setLocalSessionVariable($html_varName, "DETAIL_NAV_HISTORY",$nav_history);
225 function populateQueryWhere($isfirstview, $html_varName){
227 $this->query_where = $this->getVariableFromSession($_REQUEST['module'], 'QUERY_WHERE');
229 //this is a fail safe, in case the old ListView is still in use
230 if(empty($this->query_where)){
231 $this->query_where = $this->getLocalSessionVariable($html_varName, "QUERY_WHERE");
233 //SETTING QUERY FOR LATER USE
234 $this->setSessionVariable("QUERY_DETAIL", "where", $this->query_where);
237 $this->query_where = $this->getSessionVariable("QUERY_DETAIL", "where");
241 function processListNavigation( &$xtpl, $html_varName, $current_offset, $display_audit_link = false){
242 global $export_module, $sugar_config, $current_user;
243 //intialize audit_link
246 $row_count = $this->getListViewRowCount();
248 if($display_audit_link && (!isset($sugar_config['disc_client']) || $sugar_config['disc_client'] == false))
251 $popup_request_data = array(
252 'call_back_function' => 'set_return',
253 'form_name' => 'EditView',
254 'field_to_name_array' => array(),
256 $json = getJSONobj();
257 $encoded_popup_request_data = $json->encode($popup_request_data);
258 $audit_link = "<a href='javascript:void(0)' onclick='open_popup(\"Audit\", \"600\", \"400\", \"&record=".$_REQUEST['record']."&module_name=".$_REQUEST['module']."\", true, false, $encoded_popup_request_data);'>".$this->local_app_strings['LNK_VIEW_CHANGE_LOG']."</a>";
263 $pre_html_text .= "<tr class='pagination'>\n";
264 $pre_html_text .= "<td COLSPAN=\"20\">\n";
265 $pre_html_text .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr><td style=\"text-align: left\" > ".$audit_link."</td>\n";
269 if ($this->return_to_list_only == true) {
270 if($current_offset != 0 && $this->isRequestFromListView($html_varName))
272 if($current_offset < 0){
275 else if($current_offset > $row_count){
276 $current_offset = $row_count;
279 $this->set_base_URL($html_varName);
280 $list_URL = $this->base_URL.'&action=index&module='.$_REQUEST['module'];
281 $current_page = floor($current_offset / $this->records_per_page) * $this->records_per_page;
283 $list_URL .= '&'.$this->getSessionVariableName($html_varName,"offset").'='.$current_page;
284 //$list_link = "<a href=\"$list_URL\" >".$this->local_app_strings['LNK_LIST_RETURN']." </a>";
285 $list_link = "<button type='button' class='button' title='{$GLOBALS['app_strings']['LNK_LIST_RETURN']}' onClick='location.href=\"$list_URL\";'>".$this->local_app_strings['LNK_LIST_RETURN']."</button>";
287 $html_text .= "<td nowrap align='right' scope='row'>".$list_link;
289 if ($row_count != 0) {
290 $resume_URL = $this->base_URL.$current_offset."&InDetailNav=1";
291 //$resume_link = "<a href=\"$resume_URL\" >".$this->local_app_strings['LNK_RESUME']." </a>";
292 $resume_link = "<button type='button' class='button' title='$this->local_app_strings['LNK_RESUME']' onClick='location.href=\"$resume_URL\";'>".$this->local_app_strings['LNK_RESUME']."</button>";
294 $html_text .= " ".$resume_link;
296 $html_text .= "</td>";
300 if($current_offset != 0 && $this->isRequestFromListView($html_varName))
302 if($current_offset < 0){
305 else if($current_offset > $row_count){
306 $current_offset = $row_count;
309 $next_offset = $current_offset + 1;
310 $previous_offset = $current_offset - 1;
312 $this->set_base_URL($html_varName);
314 $start_URL = $this->base_URL."1"."&InDetailNav=1";
315 $current_URL = $this->base_URL.$current_offset."&InDetailNav=1";
316 $previous_URL = $this->base_URL.$previous_offset."&InDetailNav=1";
317 $next_URL = $this->base_URL.$next_offset."&InDetailNav=1";
318 $end_URL = $this->base_URL.$row_count."&InDetailNav=1";
320 $current_page = floor($current_offset / $this->records_per_page) * $this->records_per_page;
322 if(1 == $current_offset){
323 //$start_link = SugarThemeRegistry::current()->getImage("start_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_START'])." ".$this->local_app_strings['LNK_LIST_START'];
324 //$previous_link = SugarThemeRegistry::current()->getImage("previous_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_PREVIOUS'])." ".$this->local_app_strings['LNK_LIST_PREVIOUS']."";
325 $start_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_START']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("start_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_START'])."</button>";
326 $previous_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_PREVIOUS']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("previous_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_PREVIOUS'])."</button>";
329 //$start_link = "<a href=\"$start_URL\">".SugarThemeRegistry::current()->getImage("start","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_START'])."</a> <a href=\"$start_URL\">".$this->local_app_strings['LNK_LIST_START']."</a>";
330 $start_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_START']}' onClick='location.href=\"$start_URL\";'>".SugarThemeRegistry::current()->getImage("start","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_START'])."</button>";
332 if(0 != $current_offset){
333 //$previous_link = "<a href=\"$previous_URL\">".SugarThemeRegistry::current()->getImage("previous","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_PREVIOUS'])."</a> <a href=\"$previous_URL\" >".$this->local_app_strings['LNK_LIST_PREVIOUS']."</a>";
334 $previous_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_PREVIOUS']}' onClick='location.href=\"$previous_URL\";'>".SugarThemeRegistry::current()->getImage("previous","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_PREVIOUS'])."</button>";
337 //$previous_link = SugarThemeRegistry::current()->getImage("previous_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_PREVIOUS'])." ".$this->local_app_strings['LNK_LIST_PREVIOUS'];
338 $previous_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_PREVIOUS']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("previous_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_PREVIOUS'])."</button>";
344 if($row_count <= $current_offset){
345 //$end_link = $this->local_app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_END']);
346 //$next_link = $this->local_app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_NEXT']);
347 $end_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_END']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("end_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_END'])."</button>";
348 $next_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_NEXT']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("next_off","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_NEXT'])."</button>";
351 //$end_link = "<a href=\"$end_URL\">".$this->local_app_strings['LNK_LIST_END']."</a> <a href=\"$end_URL\">".SugarThemeRegistry::current()->getImage("end","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_END'])."</a>";
352 //$next_link = "<a href=\"$next_URL\">".$this->local_app_strings['LNK_LIST_NEXT']."</a> <a href=\"$next_URL\">".SugarThemeRegistry::current()->getImage("next","border='0' align='absmiddle'",,null,null,'.gif',$this->local_app_strings['LNK_LIST_NEXT'])."</a>";
353 $end_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_END']}' onClick='location.href=\"$end_URL\";'>".SugarThemeRegistry::current()->getImage("end","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_END'])."</button>";
354 $next_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_NEXT']}' onClick='location.href=\"$next_URL\";'>".SugarThemeRegistry::current()->getImage("next","border='0' align='absmiddle'",null,null,'.gif',$this->local_app_strings['LNK_LIST_NEXT'])."</button>";
358 $html_text .= "<td nowrap align='right' >".$start_link." ".$previous_link." (".$current_offset." ".$this->local_app_strings['LBL_LIST_OF']." ".$row_count.") ".$next_link." ".$end_link."</td>";
362 $post_html_text = "</tr></table>\n";
363 $post_html_text .= "</td>\n";
364 $post_html_text .= "</tr>\n";
365 $showVCRControl = true;
366 if(isset($sugar_config['disable_vcr'])) {
367 $showVCRControl = !$sugar_config['disable_vcr'];
369 if ( $showVCRControl && $html_text != "" )
370 $xtpl->assign("PAGINATION",$pre_html_text.$html_text.$post_html_text);
374 function set_base_URL($html_varName) {
376 if(!isset($this->base_URL)){
378 $this->base_URL = $_SERVER['PHP_SELF'];
379 if(empty($this->base_URL)){
380 $this->base_URL = 'index.php';
383 /*fixes an issue with
384 deletes when doing a search*/
385 foreach($_GET as $name=>$value){
387 if($name != $this->getSessionVariableName($html_varName,"ORDER_BY") && $name != "offset" && substr_count($name, "ORDER_BY")==0 && $name!="isfirstview"){
388 if (is_array($value)) {
389 foreach($value as $valuename=>$valuevalue){
390 $this->base_URL .= "&{$name}[]=".$valuevalue;
393 if(substr_count( $this->base_URL, '?') > 0){
394 $this->base_URL .= "&$name=$value";
396 $this->base_URL .= "?$name=$value";
403 if($_SERVER['REQUEST_METHOD'] == 'POST'){
404 $this->base_URL .= '?';
405 if(isset($_REQUEST['action'])) $this->base_URL .= '&action='.$_REQUEST['action'];
406 if(isset($_REQUEST['record'])) $this->base_URL .= '&record='.$_REQUEST['record'];
407 if(isset($_REQUEST['module'])) $this->base_URL .= '&module='.$_REQUEST['module'];
409 $this->base_URL .= "&offset=";
412 function setListViewRowCount($count)
414 $this->list_row_count = $count;
417 function getListViewRowCount()
419 return $this->list_row_count;
422 /* This method will return in all of these cases: When selecting any of the VCR buttons (start,prev,next or last)
423 * and navigating from list to detail for the first time.
424 * if false in this case: the user changes the list query (which generates a new stamp) and pastes a URL
425 * from a previously navigated item.
427 function isRequestFromListView($html_varName)
429 $varList = $this->getLocalSessionVariable($html_varName, "FROM_LIST_VIEW");
430 if(isset($_GET['stamp']) && isset($varList) && $varList == $_GET['stamp']){
439 * Return a variable from the session. uses the new ListView session data. Hence the '2'
441 * @param unknown_type $name - the name of the variable to set in the session
442 * @param unknown_type $value - the value of the variable to set
444 function getVariableFromSession($name, $value){
445 if(isset($_SESSION[$name."2_".$value])){
446 return $_SESSION[$name."2_".$value];