![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00002 /*------------------------------------------------------------------------------- 00003 * Xataface Web Application Framework 00004 * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 *------------------------------------------------------------------------------- 00020 */ 00021 00022 /****************************************************************************** 00023 * File: Dataface/ResultList.php 00024 * Author: Steve Hannah 00025 * Created: September 3, 2005 00026 * Description: 00027 * Handles creation and display of a result list from an SQL database. 00028 * 00029 *****************************************************************************/ 00030 00031 import( 'Dataface/Table.php'); 00032 import( 'Dataface/QueryBuilder.php'); 00033 import( 'Dataface/LinkTool.php'); 00034 00035 00036 class Dataface_RelatedList { 00037 00038 var $_tablename; 00039 var $_relationship_name; 00040 var $_relationship; 00041 var $_db; 00042 var $_table; 00043 var $_record; 00044 var $_start; 00045 var $_limit; 00046 var $_where; 00047 var $hideActions=false; 00048 var $noLinks=false; 00049 00050 00051 function Dataface_RelatedList( &$record, $relname, $db=''){ 00052 if ( !is_a($record, 'Dataface_Record') ){ 00053 throw new Exception("In Dataface_RelatedList constructor, the first argument is expected to be an object of type 'Dataface_Record' but received '".get_class($record)); 00054 } 00055 $this->_record =& $record; 00056 $this->_tablename = $this->_record->_table->tablename; 00057 $this->_db = $db; 00058 $this->_relationship_name = $relname; 00059 00060 00061 $this->_table =& $this->_record->_table; 00062 $this->_relationship =& $this->_table->getRelationship($relname); 00063 00064 $this->_start = isset($_REQUEST['-related:start']) ? $_REQUEST['-related:start'] : 0; 00065 $this->_limit = isset($_REQUEST['-related:limit']) ? $_REQUEST['-related:limit'] : 30; 00066 00067 $app =& Dataface_Application::getInstance(); 00068 $query =& $app->getQuery(); 00069 if ( isset($query['-related:search']) ){ 00070 $rwhere = array(); 00071 foreach ($this->_relationship->fields() as $rfield){ 00072 //list($garbage,$rfield) = explode('.', $rfield); 00073 $rwhere[] = '`'.str_replace('.','`.`',$rfield).'` LIKE \'%'.addslashes($query['-related:search']).'%\''; 00074 } 00075 $rwhere = implode(' OR ', $rwhere); 00076 } else { 00077 $rwhere = 0; 00078 } 00079 $this->_where = $rwhere; 00080 00081 00082 } 00083 00084 function _forwardButtonHtml(){ 00085 $numRecords = $this->_record->numRelatedRecords( $this->_relationship_name, $this->_where ); 00086 if ( $this->_start + $this->_limit >= $numRecords ) return ''; 00087 $query = array('-related:start'=> $this->_start+$this->_limit, '-related:limit'=>$this->_limit); 00088 $link = Dataface_LinkTool::buildLink($query); 00089 $out = '<a href="'.$link.'" title="Next '.$this->_limit.' Results"><img src="'.DATAFACE_URL.'/images/go-next.png" alt="Next" /></a>'; 00090 if ( ($this->_start+(2*$this->_limit)) < $numRecords ){ 00091 $query['-related:start'] = $numRecords - ( ($numRecords - $this->_start) % $this->_limit) -1; 00092 $link = Dataface_LinkTool::buildLink($query); 00093 $out .= '<a href="'.$link.'" title="Last"><img src="'.DATAFACE_URL.'/images/go-last.png" alt="Last" /></a>'; 00094 } 00095 return $out; 00096 } 00097 00098 function _backButtonHtml(){ 00099 if ( $this->_start <= 0 ) return ''; 00100 $query = array('-related:start'=> max( 0, $this->_start-$this->_limit), '-related:limit'=>$this->_limit); 00101 $link = Dataface_LinkTool::buildLink($query); 00102 $out = '<a href="'.$link.'" title="Previous '.$this->_limit.' Results"><img src="'.DATAFACE_URL.'/images/go-previous.png" alt="Previous" /></a>'; 00103 00104 if ( ($this->_start-$this->_limit) > 0 ){ 00105 $query['-related:start'] = 0; 00106 $out = '<a href="'.Dataface_LinkTool::buildLink($query).'" title="First"><img src="'.DATAFACE_URL.'/images/go-first.png" alt="First" /></a>'.$out; 00107 } 00108 00109 return $out; 00110 00111 } 00112 00113 function renderCell(&$record, $fieldname){ 00114 $del =& $record->_table->getDelegate(); 00115 if ( isset($del) and method_exists($del, $fieldname.'__renderCell') ){ 00116 $method = $fieldname.'__renderCell'; 00117 return $del->$method($record); 00118 //return call_user_func(array(&$del, $fieldname.'__renderCell'), $record); 00119 } 00120 return null; 00121 } 00122 00123 00124 00125 function toHtml(){ 00126 $context = array(); 00127 $context['relatedList'] = $this; 00128 $app =& Dataface_Application::getInstance(); 00129 $context['app'] =& $app; 00130 00131 $query =& $app->getQuery(); 00132 $context['query'] =& $query; 00133 00134 if ( isset( $query['-related:sort']) ){ 00135 $sortcols = explode(',', trim($query['-related:sort'])); 00136 $sort_columns = array(); 00137 foreach ($sortcols as $sortcol){ 00138 $sortcol = trim($sortcol); 00139 if (strlen($sortcol) === 0 ) continue; 00140 $sortcol = explode(' ', $sortcol); 00141 if ( count($sortcol) > 1 ){ 00142 $sort_columns[$sortcol[0]] = strtolower($sortcol[1]); 00143 } else { 00144 $sort_columns[$sortcol[0]] = 'asc'; 00145 } 00146 break; 00147 } 00148 unset($sortcols); // this was just a temp array so we get rid of it here 00149 } else { 00150 $sort_columns = array(); 00151 } 00152 $context['sort_columns'] =& $sort_columns; 00153 00154 $sort_columns_arr = array(); 00155 foreach ( $sort_columns as $colkey=>$colorder) { 00156 $sort_columns_arr[] = '`'.$colkey.'`'. $colorder; 00157 } 00158 if ( count($sort_columns_arr) > 0 ){ 00159 $sort_columns_str = implode(', ',$sort_columns_arr); 00160 } else { 00161 $sort_columns_str = 0; 00162 } 00163 00164 00165 00166 unset($query); 00167 00168 00169 $skinTool =& Dataface_SkinTool::getInstance(); 00170 $context['skinTool'] =& $skinTool; 00171 00172 $resultController =& $skinTool->getResultController(); 00173 $context['resultController'] =& $resultController; 00174 00175 $s =& $this->_table; 00176 $r =& $this->_relationship->_schema; 00177 $fkeys = $this->_relationship->getForeignKeyValues(); 00178 $default_order_column = $this->_relationship->getOrderColumn(); 00179 00180 //echo "Def order col = $default_order_column"; 00181 ob_start(); 00182 df_display(array('redirectUrl'=>$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING']), 'Dataface_MoveUpForm.html'); 00183 $moveUpForm = ob_get_contents(); 00184 ob_end_clean(); 00185 $context['moveUpForm'] = $moveUpForm; 00186 00187 00188 00189 00190 00191 $records =& $this->_record->getRelatedRecords($this->_relationship_name, true, $this->_start, $this->_limit, $this->_where); 00192 00193 if ( PEAR::isError($records) ){ 00194 $records->addUserInfo("Error retrieving records from relationship ".$this->_relationship_name); 00195 return $records; 00196 } 00197 $context['records'] =& $records; 00198 00199 //echo "<br/><b>Now Showing</b> ".($this->_start+1)." to ".(min($this->_start + $this->_limit, $this->_record->numRelatedRecords($this->_relationship_name))); 00200 $perms = $this->_record->getPermissions(array('relationship'=>$this->_relationship_name)); 00201 $context['perms'] = $perms; 00202 $context['record_editable'] = Dataface_PermissionsTool::edit($this->_record); 00203 $context['can_add_new_related_record'] = @$perms['add new related record']; 00204 $context['can_add_existing_related_record'] = @$perms['add existing related record']; 00205 00206 if ( !$this->hideActions and ($context['record_editable'] or @$perms['add new related record'] or @$perms['add existing related record']) ){ 00207 $query = array('-action'=>'new_related_record'); 00208 $link = Dataface_LinkTool::buildLink($query); 00209 $context['new_related_record_query'] = $query; 00210 $context['new_related_record_link'] = $link; 00211 00212 $domainTable = $this->_relationship->getDomainTable(); 00213 //$context['domainTable'] =& $domainTable; 00214 $importTablename = $domainTable; 00215 if ( !PEAR::isError($domainTable) ){ 00216 //This relationship is many-to-many so we can add existing records to it. 00217 $query2 = array('-action'=>'existing_related_record'); 00218 $context['existing_related_record_query'] = $query2; 00219 $link2 = Dataface_LinkTool::buildLink($query2); 00220 $context['existing_related_record_link'] = $link2; 00221 00222 $destTables = $this->_relationship->getDestinationTables(); 00223 $context['destTables'] =& $destTables; 00224 $importTablename = $destTables[0]->tablename; 00225 $context['importTablename'] = $importTablename; 00226 } 00227 if ( !PEAR::isError($importTablename) ){ 00228 $importTable =& Dataface_Table::loadTable($importTablename); 00229 $context['importTable'] =& $importTable; 00230 $query3 = array('-action'=>'import'); 00231 $context['import_related_records_query'] =& $query3; 00232 $link3 = Dataface_LinkTool::buildLink($query3); 00233 $context['import_related_records_link'] = $link3; 00234 } 00235 00236 00237 00238 } 00239 00240 $imgIcon = DATAFACE_URL.'/images/search_icon.gif'; 00241 $searchSrc = DATAFACE_URL.'/js/Dataface/RelatedList/search.js'; 00242 $relname = $this->_relationship_name; 00243 $context['relationship_label'] = $this->_relationship->getLabel(); 00244 $context['relname'] = $relname; 00245 $context['relationship_name'] = $this->_relationship_name; 00246 $context['searchSrc'] = $searchSrc; 00247 $context['imgIcon'] = $imgIcon; 00248 00249 00250 if ( !$this->hideActions ){ 00251 $num_related_records = $this->_record->numRelatedRecords($this->_relationship_name, $this->_where); 00252 $now_showing_start = $this->_start+1; 00253 $now_showing_finish = min($this->_start + $this->_limit, $this->_record->numRelatedRecords($this->_relationship_name, $this->_where)); 00254 00255 $stats_context = array( 00256 'num_related_records'=>$num_related_records, 00257 'now_showing_start'=>$now_showing_start, 00258 'now_showing_finish'=>$now_showing_finish, 00259 'relationship_name'=>$this->_relationship_name, 00260 'limit_field'=>$resultController->limitField('related:'), 00261 'back_link'=>$this->_backButtonHtml(), 00262 'next_link'=>$this->_forwardButtonHtml() 00263 00264 ); 00265 00266 import('Dataface/ActionTool.php'); 00267 $at =& Dataface_ActionTool::getInstance(); 00268 $actions = $at->getActions(array( 00269 'category'=>'related_list_actions' 00270 ) 00271 ); 00272 00273 $context['related_list_actions'] = $actions; 00274 foreach ($stats_context as $k=>$v) $context[$k] = $v; 00275 00276 00277 00278 00279 } 00280 00281 00282 import('Dataface/ActionTool.php'); 00283 $at =& Dataface_ActionTool::getInstance(); 00284 $selected_actions = $at->getActions(array('category'=>'selected_related_result_actions')); 00285 $context['selected_actions'] = $selected_actions; 00286 00287 if ( $this->_relationship->_schema['list']['type'] == 'treetable' ){ 00288 import('Dataface/TreeTable.php'); 00289 $treetable = new Dataface_TreeTable($this->_record, $this->_relationship->getName()); 00290 $context['treetable'] = $treetable->toHtml(); 00291 } else { 00292 echo $moveUpForm; 00293 if ( !$this->hideActions and $this->_where ){ 00294 00295 $filterQuery =& $app->getQuery(); 00296 $context['filterQuery'] =& $filterQuery; 00297 00298 } 00299 if ( count($records) > 0 ){ 00300 00301 ob_start(); 00302 echo ' 00303 <table class="listing relatedList relatedList--'.$this->_tablename.' relatedList--'.$this->_tablename.'--'.$this->_relationship_name.'" id="relatedList"> 00304 <thead> 00305 <tr>'; 00306 00307 if ( count($selected_actions)>0){ 00308 echo '<th>'; 00309 if ( !$this->hideActions ){ 00310 echo '<input type="checkbox" onchange="toggleSelectedRows(this,\'relatedList\');">'; 00311 } 00312 echo '</th>'; 00313 } 00314 $cols = array_keys(current($records)); 00315 00316 00317 00318 $col_tables = array(); 00319 $table_keys = array(); 00320 00321 $usedColumns = array(); 00322 foreach ($cols as $key ){ 00323 if ( $key == $default_order_column ) continue; 00324 if ( is_int($key) ) continue; 00325 if ( isset($sort_columns[$key]) ){ 00326 $class = 'sorted-column-'.$sort_columns[$key]; 00327 $query = array(); 00328 $qs_columns = $sort_columns; 00329 unset($qs_columns[$key]); 00330 $sort_query = $key.' '.($sort_columns[$key] == 'desc' ? 'asc' : 'desc'); 00331 foreach ( $qs_columns as $qcolkey=> $qcolvalue){ 00332 $sort_query .= ', '.$qcolkey.' '.$qcolvalue; 00333 } 00334 } else { 00335 $class = 'unsorted-column'; 00336 $sort_query = $key.' asc'; 00337 foreach ( $sort_columns as $scolkey=>$scolvalue){ 00338 $sort_query .= ', '.$scolkey.' '.$scolvalue; 00339 } 00340 00341 } 00342 $sq = array('-related:sort'=>$sort_query); 00343 $link = Dataface_LinkTool::buildLink($sq); 00344 00345 $fullpath = $this->_relationship_name.'.'.$key; 00346 00347 $field =& $s->getField($fullpath); 00348 if ( isset( $this->_relationship->_schema['visibility'][$key]) and $this->_relationship->_schema['visibility'][$key] == 'hidden' ) continue; 00349 if ( $field['visibility']['list'] != 'visible') continue; 00350 if ( $s->isBlob($fullpath) or $s->isPassword($fullpath) ) continue; 00351 if ( PEAR::isError($field) ){ 00352 $field->addUserInfo("Error getting field info for field $key in RelatedList::toHtml() "); 00353 return $field; 00354 } 00355 $usedColumns[] = $key; 00356 00357 $label = $field['widget']['label']; 00358 if ( isset($field['column']) and @$field['column']['label'] ){ 00359 $label = $field['column']['label']; 00360 } 00361 00362 $legend = ''; 00363 if ( @$field['column'] and @$field['column']['legend'] ){ 00364 $legend = '<span class="column-legend">'.htmlspecialchars($field['column']['legend']).'</span>'; 00365 00366 } 00367 if (!$this->noLinks ){ 00368 echo '<th><a href="'.htmlspecialchars($link).'">'.htmlspecialchars($field['widget']['label'])."</a> $legend</th>\n"; 00369 } else { 00370 echo '<th>'.$field['widget']['label'].'</th>'; 00371 } 00372 if ( !isset($col_tables[$key]) ) $col_tables[$key] = $field['tablename']; 00373 if (!isset($table_keys[$col_tables[$key]]) ){ 00374 $table_table =& Dataface_Table::loadTable($field['tablename']); 00375 $table_keys[$col_tables[$key]] = array_keys($table_table->keys()); 00376 unset($table_table); 00377 } 00378 unset($field); 00379 00380 00381 } 00382 echo "</tr> 00383 </thead> 00384 <tbody id=\"relatedList-body\"> 00385 "; 00386 00387 $limit = min( $this->_limit, $this->_record->numRelatedRecords($this->_relationship_name, $this->_where)-$this->_start); 00388 $relatedTable = $this->_relationship->getDomainTable(); 00389 if ( PEAR::isError($relatedTable) ){ 00390 $relatedTable = reset($r['selected_tables']); 00391 } 00392 $relatedTable = Dataface_Table::loadTable($relatedTable); 00393 00394 $relatedKeys = array_keys($relatedTable->keys()); 00395 foreach (array_keys($relatedKeys) as $i){ 00396 $relatedKeys[$i] = $this->_relationship_name.".".$relatedKeys[$i]; 00397 } 00398 00399 $fullpaths = array(); 00400 $fields_index=array(); 00401 foreach( $usedColumns as $key ){ 00402 $fullpaths[$key] = $this->_relationship_name.'.'.$key; 00403 $fields_index[$key] =& $s->getField($fullpaths[$key]); 00404 00405 00406 } 00407 00408 $evenRow = false; 00409 00410 00411 for ( $i=$this->_start; $i<($this->_start+$limit); $i++){ 00412 $rowClass = $evenRow ? 'even' : 'odd'; 00413 $evenRow = !$evenRow; 00414 00415 if ( $default_order_column and @$perms['reorder_related_records'] ){ 00416 $style = 'cursor:move'; 00417 // A variable that will be used below in javascript to decide 00418 // whether to make the table sortable or not 00419 $sortable_js = 'true'; 00420 } else { 00421 $style = ''; 00422 $sortable_js = 'false'; 00423 } 00424 $context['sortable_js'] = $sortable_js; 00425 00426 00427 unset($rrec); 00428 $rrec = $this->_record->getRelatedRecord($this->_relationship_name, $i,$this->_where, $sort_columns_str);//new Dataface_RelatedRecord($this->_record, $this->_relationship_name, $this->_record->getValues($fullpaths, $i, 0, $sort_columns_str)); 00429 $rrecid = $rrec->getId(); 00430 00431 echo "<tr class=\"listing $rowClass\" style=\"$style\" id=\"row_$rrecid\">"; 00432 if ( count($selected_actions)>0){ 00433 echo ' 00434 <td class="'.$rowClass.' viewableColumn" nowrap>'; 00435 if ( !$this->hideActions ){ 00436 echo '<input xf-record-id="'.htmlspecialchars($rrecid).'" class="rowSelectorCheckbox" id="rowSelectorCheckbox:'.htmlspecialchars($rrecid).'" type="checkbox">'; 00437 } 00438 echo '</td>'; 00439 } 00440 00441 00442 $link_queries=array(); 00443 foreach ($usedColumns as $key){ 00444 if ( is_int($key) ) continue; 00445 00446 $fullpath = $fullpaths[$key]; 00447 unset($field); 00448 $field =& $fields_index[$key];//$s->getField($fullpath); 00449 $srcRecord =& $rrec->toRecord($field['tablename']); 00450 $link = $srcRecord->getURL('-action=browse'); 00451 $srcRecordId = $srcRecord->getId(); 00452 00453 $val = $this->_record->preview($fullpath, $i,255, $this->_where, $sort_columns_str); 00454 $title = ""; 00455 00456 if ( $key == $default_order_column ){ 00457 unset($field); 00458 unset($srcRecord); 00459 continue; 00460 00461 } else { 00462 if ($val != 'NO ACCESS'){ 00463 $accessClass = 'viewableColumn'; 00464 } else { 00465 00466 $accessClass = ''; 00467 } 00468 $cellClass = 'resultListCell resultListCell--'.$key; 00469 $cellClass .= ' '.$srcRecord->table()->getType($key); 00470 $renderVal = $this->renderCell($srcRecord, $field['Field']); 00471 if ( isset($renderVal) ) $val = $renderVal; 00472 else if ( $link and !@$field['noLinkFromListView'] and !$this->noLinks and $srcRecord->checkPermission('link')) $val = "<a href=\"".htmlspecialchars($link)."\" title=\"". htmlspecialchars($title)."\" data-xf-related-record-id=\"".htmlspecialchars($srcRecordId)."\" class=\"xf-related-record-link\">".$val."</a>"; 00473 echo "<td class=\"$cellClass $rowClass $accessClass\">$val</td>\n"; 00474 unset($srcRecord); 00475 } 00476 00477 } 00478 echo "</tr>\n"; 00479 } 00480 00481 echo "</tbody> 00482 </table>"; 00483 00484 $related_table_html = ob_get_contents(); 00485 $context['related_table_html'] = $related_table_html; 00486 ob_end_clean(); 00487 00488 if ( !$this->hideActions ){ 00489 ob_start(); 00490 00491 echo '<form id="result_list_selected_items_form" method="post">'; 00492 $app =& Dataface_Application::getInstance(); 00493 $q =& $app->getQuery(); 00494 foreach ( $q as $key=>$val){ 00495 if ( strlen($key)>1 and $key{0} == '-' and $key{1} == '-' ){ 00496 continue; 00497 } 00498 echo '<input type="hidden" name="'.$key.'" value="'.htmlspecialchars($val).'">'; 00499 } 00500 echo '<input type="hidden" name="--selected-ids" id="--selected-ids">'; 00501 echo '<input type="hidden" name="-from" id="-from" value="'.$query['-action'].'">'; 00502 echo '</form>'; 00503 $selected_actions_form = ob_get_contents(); 00504 $context['selected_actions_form'] = $selected_actions_form; 00505 ob_end_clean(); 00506 00507 00508 00509 00510 // This bit of javascript goes through all of the columns and removes all columns that 00511 // don't have any accessible information for this query. (i.e. any columns for which 00512 // each row's value is 'NO ACCESS' is removed 00513 $prototype_url = DATAFACE_URL.'/js/scriptaculous/lib/prototype.js'; 00514 $context['prototype_url'] = $prototype_url; 00515 $scriptaculous_url =DATAFACE_URL.'/js/scriptaculous/src/scriptaculous.js'; 00516 $context['scriptaculous_url'] = $scriptaculous_url; 00517 $effects_url = DATAFACE_URL.'/js/scriptaculous/src/effects.js'; 00518 $context['effects_url'] = $effects_url; 00519 $dragdrop_url = DATAFACE_URL.'/js/scriptaculous/src/dragdrop.js'; 00520 $context['dragdrop_url'] = $dragdrop_url; 00521 $thisRecordID = $this->_record->getId(); 00522 $context['thisRecordID'] = $thisRecordID; 00523 00524 } 00525 00526 } 00527 00528 00529 00530 } 00531 00532 ob_start(); 00533 df_display($context, 'xataface/RelatedList/list.html'); 00534 $out = ob_get_contents(); 00535 ob_end_clean(); 00536 00537 return $out; 00538 } 00539 00540 00541 00542 } 00543