Xataface  2.0alpha2
Xataface Application Framework
 All Data Structures Namespaces Files Functions Variables Groups Pages
ResultController.php
Go to the documentation of this file.
1 <?php
2 /*-------------------------------------------------------------------------------
3  * Xataface Web Application Framework
4  * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *-------------------------------------------------------------------------------
20  */
21 /*******************************************************************************
22 * File: Dataface/ResultController.php
23 * Author: Steve Hannah <shannah@sfu.ca>
24 * Description:
25 * Allows for database controlling . Forward back, etc.. functionality
26 *
27 ******************************************************************************/
28 
29 import( 'Dataface/QueryBuilder.php');
30 import( 'Dataface/Table.php');
31 import( 'Dataface/LinkTool.php');
32 
33 $GLOBALS['Dataface_ResultController_limit'] = 20;
34 $GLOBALS['Dataface_ResultController_skip'] = 0;
35 
36 
38 
39  var $_baseUrl;
44  var $_fields;
45  var $_table;
46  var $_db;
47  var $_records;
48  var $_pos;
50  var $_query;
52  var $type;
53 
54 
59 
60 
65 
67 
68 
69  function Dataface_ResultController($tablename, $db='', $baseUrl='', $query=''){
70  $this->_tablename = $tablename;
71  $this->_db = $db;
72  $this->_baseUrl = $baseUrl ? $baseUrl : $_SERVER['PHP_SELF'];
74 
75  $this->_table =& Dataface_Table::loadTable($this->_tablename);
76  $this->_fields =& $this->_table->fields();
77 
78  if ( !$query ){
79  $this->_query =& $app->getQuery();
80  $query =& $this->_query;
81  $this->_queryBuilder = new Dataface_QueryBuilder($this->_query['-table'], $query);
82  $this->_resultSet =& $app->getResultSet();
83 
84  } else {
85 
86  if ( !is_array($query) ){
87  $query = array("-mode"=>$app->_conf['default_mode']);
88  }
89 
90  $this->_resultSet =& Dataface_QueryTool::loadResult($tablename, $db, $query);
91 
92 
93 
94 
95  if ( !isset( $query['-limit']) ){
96  $query['-limit'] = $GLOBALS['Dataface_ResultController_limit'];
97  }
98  if ( !isset( $query['-skip']) ){
99  $query['-skip'] = $GLOBALS['Dataface_ResultController_skip'];
100  }
101  if ( !isset( $query['-cursor'] ) ){
102  $query['-cursor'] = $query['-skip'];
103  }
104  if ( !isset( $query['-mode'] ) ){
105  $query['-mode'] = $app->_conf['default_mode'];
106  }
107 
108  $this->_queryBuilder = new Dataface_QueryBuilder($this->_tablename, $query);
109  $this->_query =& $this->_queryBuilder->_query;
110  }
111 
112  // set the title column
113  foreach ($this->_fields as $field){
114  if ( preg_match('/char/i', $field['Type']) ){
115  $this->_titleColumn = $field['name'];
116  break;
117  }
118  }
119 
120  if ( !isset($this->_titleColumn) ){
121  reset($this->_fields);
122  $field = current($this->_fields);
123  $this->_titleColumn = $field['name'];
124  }
125 
126  // set the position
127  $this->_pos = $query['-cursor'];
128 
129 
130  $this->_displayedRecords = $query['-limit'];
131 
132 
133  }
134 
135 
136  function &getRecords(){
137  if ( !isset( $this->_records) ){
138  $this->_records = array();
139 
140  $sql = $this->_queryBuilder->select();
141 
142  $sqlStats = $this->_queryBuilder->select_num_rows();
143  $db =& Dataface_DB::getInstance();
144  $res = $db->query($sqlStats, $this->_table->db, null, true);
145  //if ( !$res and !is_array($res) ){
146  $this->_totalRecords = $res[0]['num'];
147  //list($this->_totalRecords) = mysql_fetch_row( mysql_query( $sqlStats, $this->_db ) );
148 
149 
150  //$res = mysql_query($sql, $this->_db);
151  $res = $db->query($sql, $this->_table->db, null, true);
152 
153  if ( !$res and !is_array($res) ){
154  throw new Exception("An error occurred attempting to retrieve records from the database.: ".mysql_error($this->db), E_USER_ERROR);
155  }
156  $this->_displayedRecords = count($res);
157 
158  //while ( $row = mysql_fetch_array($res) ){
159  foreach ($res as $row){
160  $this->_records[] = $row;
161  }
162 
163  }
164 
165  return $this->_records;
166 
167  }
168 
169 
170  function getCurrentPosition(){
171 
172  return $this->_pos;
173  }
174 
175  function setBaseUrl( $url ){
176  $this->_baseUrl = $url;
177  }
178 
179  function getBaseUrl(){
180  if ( !isset($this->_basUrl) ){
181  $this->_baseUrl = $_SERVER['PHP_SELF'];
182  }
183 
184  return $this->_baseUrl;
185 
186  }
187 
188  // Gets the number of records in this found set.
189  function getTotalRecords(){
190  if (!isset( $this->_totalRecords) ){
191  $db =& Dataface_DB::getInstance();
192  $res = $db->query($this->_queryBuilder->select_num_rows(), $this->_table->db, null, true);
193  $this->_totalRecords = $res[0]['num'];
194  //list($this->_totalRecords) = mysql_fetch_row( mysql_query( $this->_queryBuilder->select_num_rows() ) );
195 
196  }
197 
198  return $this->_totalRecords;
199 
200  }
201 
202 
205  }
206 
207 
211  function getPageIndex(&$selected_url){
212  $totalRecords = $this->getTotalRecords();
213  $pageNumber = 1;
214  $contents = array();
215 
216  for ( $i=0; $i<$totalRecords; $i+=$this->_query['-limit']){
217  $query = /*array_merge($this->_query, */array("-skip"=>$i, "-action"=>"list")/*)*/;
218  $link = $this->_buildLink($query);
219  $contents[$link] = $pageNumber++;
220 
221  if ( $this->_resultSet->start() >= $i and $this->_resultSet->start() < ($i+$this->_query['-limit'])){
222  $selected_url = $link;
223  }
224  }
225 
226  return $contents;
227 
228  }
229 
230 
231 
235  function getContentsList($selected_url){
236 
237  if (! isset( $this->_contentsList) ){
238 
239  $this->_contentsList = array();
240  if ( $this->getTotalRecords() > 100 ){
241  // there are over 100 records in this found set. It is unfeasible
242  // to list them all in the jump menu, so instead we will list ranges
243  // of records
244  //$totalRecords = $this->getTotalRecords();
245  //for ( $i=0; $i<$totalRecords; $i+=$this->_query['-limit']){
246  // $query = array_merge($this->_query, array("-skip"=>$i, "-action"=>"list"));
247  // $link = $this->_buildLink($query);
248  // $this->_contentsList[$link] = ($i+1)." to ".($i+$this->_query['-limit']);
249  //
250  // if ( $this->_resultSet->start() >= $i and $this->_resultSet->start() < ($i+$this->_query['-limit'])){
251  // $selected_url = $link;
252  // }
253  //}
254 
255 
256  } else {
257  // There are less than 100 records.. Just list them individually
258  //$sql = $this->_queryBuilder->select(
259  // array($this->_titleColumn),
260  // array('-skip'=>null, '-limit'=>null)
261  // );
262 
263  //$res = mysql_query(
264  // $sql,
265  // $this->_db
266  //);
267  $titles = $this->_resultSet->getTitles(false, true,false);
268  $index = 0;
269  //while ( $row = mysql_fetch_array($res) ){
270  $len = count($titles);
271 
272  for ($index =0 ; $index < $len; $index++){
273  //$query = array( "-cursor"=>$index++, "-action"=>'browse');
274  $query = array( "-cursor"=>$index, "-action"=>'browse');
275  $query = array_merge( $this->_query, $query);
276  foreach ($query as $key=>$value) {
277  if ( $value === null ){
278  unset($query[$key]);
279  }
280  }
281  $link = $this->_buildSetLink($query) ;
282 
283  //$this->_contentsList[ $link ] = $row[0];
284  $this->_contentsList[ $link ] = $titles[$index];
285 
286  //if ( $index-1 == $this->_query['-cursor'] ){
287  if ( $index == $this->_query['-cursor'] ){
288  $selected_url = $link;
289  }
290  }
291  }
292  }
293 
294 
295 
296  return $this->_contentsList;
297 
298 
299  }
300 
301 
302  function _buildSetLink($query=array()){
303  return Dataface_LinkTool::buildSetLink($query);
304  }
305 
310  function _buildLink($query=array()){
311 
312  return Dataface_LinkTool::buildLink($query);
313  }
314 
315  function jumpMenu(){
316  $contents = $this->getContentsList($selected_url);
317  if ( $contents ){
318  $html = '<select name="controller" class="jumpMenu" onchange="javascript:window.location=this.options[this.selectedIndex].value;">
319 
320  ';
321  $selected_url = '';
322  $currentLink = Dataface_LinkTool::buildLink(array());
323  $currentLink = preg_replace('/&?-limit=\d+/', '', $currentLink);
324  // link sans limit for use in field to specify number of records to be displayed per page
325 
326  foreach ($contents as $key=>$value){
327 
328  $selected = $key==$selected_url ? "selected" : '';
329  $html .= '
330  <option value="'.$key.'" '.$selected.'>'.$value.'</option>';
331  }
332  $html .= '</select>';
333  } else {
334  $html = '';
335  }
336  return $html;
337 
338  }
339 
340  function limitField($prefix=''){
341  $currentLink = Dataface_LinkTool::buildLink(array('-'.$prefix.'limit'=>null, '-'.$prefix.'skip'=>0));
342  if ( !$prefix ) {
343  $limitval = $this->_resultSet->limit();
344  } else if (isset($_GET['-'.$prefix.'limit'])){
345  $limitval = $_GET['-'.$prefix.'limit'];
346  } else {
347  $limitval = 30;
348  }
349  return '(Display <input type="text" value="'.$limitval.'" onchange="window.location = \''.$currentLink.'&-'.$prefix.'limit=\'+this.value" size="3"/> Records per page)';
350  }
351 
352 
353  function toHtml($prefix=''){
355  $query =& $app->getQuery();
356  if ( !isset($this->type) ) $this->type = $query['-mode'];
357 
358  switch ( $this->type ){
359  case 'browse':
360  return $this->browseHtml($prefix);
361  default:
362  return $this->listHtml($prefix);
363  }
364 
365  }
366 
367  function listHtml($prefix=''){
369  $rs =& $this->_resultSet;
370  $pages = array();
371  $start = $rs->start();
372  $end = $rs->end();
373  $limit = max($rs->limit(),1);
374  $found = $rs->found();
375 
376  // we show up to 5 pages on either side of the current position
377  $pages_before = ceil(floatval($start)/floatval($limit));
378  $pages_after = ceil(floatval($found-$end-1)/floatval($limit));
379  $curr_page = $pages_before + 1;
380  $total_pages = $pages_before+$pages_after+1;
381 
382  //$i = $curr_page;
383  $i_start = $start;
384  for ( $i = $curr_page; $i>max(0,$curr_page-5); $i-- ){
385  $pages[$i] = $app->url('-'.$prefix.'limit='.$limit.'&-'.$prefix.'skip='.max($i_start,0));
386  if ( $this->_baseUrl ) $pages[$i] = $this->_baseUrl.'?'.substr($pages[$i], strpos($pages[$i], '?')+1);
387  $i_start -= $limit;
388  }
389  //$i = $curr_page+1;
390  $i_start = $start+$limit;
391  for ($i = $curr_page+1; $i<=min($total_pages,$curr_page+5); $i++){
392  $pages[$i] = $app->url('-'.$prefix.'limit='.$limit.'&-'.$prefix.'skip='.$i_start);
393  if ( $this->_baseUrl ) $pages[$i] = $this->_baseUrl.'?'.substr($pages[$i], strpos($pages[$i], '?')+1);
394  $i_start += $limit;
395  }
396  ksort($pages);
397 
398  $pages2 = array();
399  if ( $curr_page > 1 ){
400  $pages2[df_translate('scripts.GLOBAL.LABEL_PREV','Prev')] = $pages[$curr_page-1];
401  }
402 
403  foreach ( $pages as $pageno=>$pageval){
404  $pages2[$pageno] = $pageval;
405  }
406 
407  if ( $curr_page < $total_pages ){
408 
409  $pages2[df_translate('scripts.GLOBAL.LABEL_NEXT','Next')] = $pages[$curr_page+1];
410  }
411  $out = array('<ul class="resultController">');
412  $out[] = '<li class="rs-description">'.df_translate('scripts.GLOBAL.MESSAGE_FOUND','Found '.$found.' records', array('found'=>$found)).' </li>';
413  foreach ($pages2 as $pageno=>$link){
414  if ( $pageno == $curr_page ) $selected = ' selected';
415  else $selected = '';
416  $out[] = '<li class="'.$selected.'"><a href="'.htmlspecialchars($link).'">'.$pageno.'</a></li>';
417  }
418  $appurl = $app->url('');
419  $appurl = preg_replace('/[&\?]'.preg_quote('-'.$prefix.'limit=').'[^&]*/', '', $appurl);
420  $appurl = preg_replace('/[&\?]'.preg_quote('-'.$prefix.'skip=').'[^&]*/', '', $appurl);
421  $urlprefix = ( $this->_baseUrl ? $this->_baseUrl.'?'.substr($appurl,strpos($appurl,'?')+1) : $appurl);
422  $out[] = '<li class="results-per-page"> '.df_translate('scripts.GLOBAL.LABEL_SHOWING', 'Showing').' <input type="text" value="'.$limit.'" onchange="window.location = \''.$urlprefix.'&-'.$prefix.'limit=\'+this.value" size="3"/>'.df_translate('scripts.GLOBAL.MESSAGE_RESULTS_PER_PAGE','Results per page');
423  $out[] = '</ul>';
424 
425  return implode("\n",$out);
426  }
427 
428  function browseHtml($prefix){
429 
430 
431 
432  $html = '
433  <div class="resultController">
434 
435  <div class="container"><div class="controllerJumpMenu">
436  <b>Jump: </b>';
437  $html .= $this->jumpMenu().'</div>
438 
439  </div>
440 
441 
442  <table class="forwardBackTable" width="100%" border="0" cellpadding="0" cellspacing="5"><tr><td width="33%" valign="top" align="left" bgcolor="#eaeaea">
443  '. $this->getPrevLinkHtml().'
444  </td><td width="34%" valign="top" align="center">
445 
446  '. $this->getCurrentHtml();
447 
448  if ( $this->_query['-mode'] == 'list' ) {
449  $html .='<br/>'.$this->limitField();
450 
451  }
452 
453  $html .= '
454 
455  </td><td width="33%" valign="top" align="right" bgcolor="#eaeaea">
456 
457  '. $this->getNextLinkHtml().'
458  </td>
459  </tr>
460  </table>
461  </div>
462  ';
463  return $html;
464  }
465 
466  function getLinkHtml($pos, $linkId=null,$imgURL = null, $imgAlt="Go", $mode=null){
467  $mode = $mode ? $mode : $this->_query['-mode'];
468  if ( $pos<0 ) return '';
469 
470  $url = $this->_buildSetLink(
471  array('-cursor'=>$pos)
472  );
473 
474  if ( $mode == 'browse' ){
475  $title = $pos.'';
476 
477  } else if ( $mode == 'list' ){
478  $from = $pos;
479  $to = min( $pos + $this->_resultSet->limit(), $this->_resultSet->found() );
480  $title = "Records ".($from+1)." to ".($to);
481  $url = $this->_buildLink(
482  array('-skip'=>$from)
483  );
484 
485  }
486  if ( $linkId !== null ){
487  $id = " id=\"$linkId\"";
488  } else {
489  $id = '';
490  }
491  if ( isset($imgURL) ){
492  return '<a href="'.$url.'"'.$id.' title="'.$title.'"><img src="'.$imgURL.'" alt="'.$imgAlt.'" /></a>';
493  } else {
494  return '<a href="'.$url.'"'.$id.' title="'.$title.'">'.$imgAlt.'</a>';
495  }
496  }
497 
498  function getPrevLinkHtml($img=null, $mode=null){
499  if ( !isset($img) ){
500  $img = DATAFACE_URL.'/images/go-previous.png';
501  }
502  $mode = $mode ? $mode : $this->_query['-mode'];
503 
504  if ( $mode =='browse'){
505  if ( $this->_resultSet->cursor()<=0 ) return '';
506  return $this->getLinkHtml(
507  $this->_resultSet->cursor()-1,
508  'prevLink',
509  $img,
510  '&lt;&lt;Back',
511  $mode);
512  } else if ( $mode =='list') {
513  if ( $this->_resultSet->start()<=0 ) return '';
514  return $this->getLinkHtml(
515  max(
516  $this->_resultSet->start()-$this->_resultSet->limit(),
517  0
518  ),
519  'prevLink',
520  $img,
521  '&lt;&lt;Back',
522  $mode );
523  } else {
524  return '';
525  }
526  }
527 
528  function getNextLinkHtml($img=null, $mode=null){
529  if ( !isset($img) ) $img = DATAFACE_URL.'/images/go-next.png';
530  $mode = $mode ? $mode : $this->_query['-mode'];
531  if ( $mode=='browse' && $this->_resultSet->cursor()+1 < $this->_resultSet->found()){
532  return $this->getLinkHtml(
533  $this->_resultSet->cursor()+1,
534  'nextLink',
535  $img,
536  'Next&gt;&gt;',
537  $mode
538  );
539  } else if ( $mode=='list' and $this->_resultSet->end()+1 < $this->_resultSet->found() ) {
540  return $this->getLinkHtml(
541  $this->_resultSet->end()+1,
542  'nextLink',
543  $img,
544  'Next&gt;&gt;',
545  $mode
546  );
547  } else {
548  return '';
549  }
550  }
551 
552  function getCurrentHtml(){
553 
554  if ( $this->_query['-mode'] == 'list' ){
555  return "<b>Now Showing:</b> ".$this->getLinkHtml($this->_resultSet->start(), 'currentLink');
556  } else if ($this->_query['-mode'] == 'browse' ) {
557 
558  return "<b>This Record: </b>".$this->getLinkHtml($this->_resultSet->cursor(), 'currentLink');
559  } else {
560  return '';
561  }
562  }
563 
564  function getPageIndexHtml(){
565  if ( $this->_query['-mode'] == 'list' ){
566  $selected = '';
567  $pages = $this->getPageIndex($selected);
568  ob_start();
569  echo '<ul class="page-index">';
570  $count = 0;
571  foreach ( $pages as $link=>$title ){
572  if ( $count++ > 8 ){
573  echo '<li>...</li>
574  ';
575  break;
576  } else if ( $link == $selected ){
577  echo '<li class="selected-page">'.$title.'</li>
578  ';
579  } else {
580  echo '<li><a href="'.$link.'">'.$title.'</a></li>
581  ';
582  }
583  }
584  echo '</ul>';
585  $out = ob_get_contents();
586  ob_end_clean();
587  return $out;
588  }
589  return '';
590  }
591 
592 
593 
594 }