2013-04-22 05:50:28 +00:00
< ? php defined ( 'SYSPATH' ) or die ( 'No direct access allowed.' );
/**
* This class is for rendering a table of data .
*
* @ package lnApp
2013-10-08 23:24:11 +00:00
* @ category Helpers
2013-04-22 05:50:28 +00:00
* @ author Deon George
* @ copyright ( c ) 2009 - 2013 Deon George
* @ license http :// dev . leenooks . net / license . html
*/
abstract class lnApp_Table {
2013-05-07 01:38:28 +00:00
private $data = NULL ;
private $columns = array (); // Our columns that we need to display
2013-05-14 13:55:30 +00:00
private $filters = array (); // Our datafomrating that we need to use
private $filters_added = FALSE ;
2013-05-07 01:38:28 +00:00
private $jssort = FALSE ; // Use the JS pager and sorter
private $other = '' ; // If we are only listing x items, this will be the other summary line
private $other_col = NULL ; // If we are only listing x items, this will be the other summary line
private $po = NULL ; // If we are paging the results, this is the page we are displaying
private $page = FALSE ; // If we should page the results
private $page_rows = 0 ; // Number of rows per page
2013-11-20 02:26:02 +00:00
private $prepend = array (); // Our data formating that we need to use, prepended to the value
private $postproc = array (); // Our data formating that we need to use after the value is determined
2013-05-14 13:55:30 +00:00
private $select = array (); // Our select form details
2013-05-07 01:38:28 +00:00
public function __toString () {
2013-06-06 11:25:25 +00:00
try {
2013-11-20 02:26:02 +00:00
return ( string ) $this -> render ();
2013-06-06 11:25:25 +00:00
} catch ( Exception $e ) {
return $e -> getMessage ();
}
2013-05-07 01:38:28 +00:00
}
public function columns ( $cols ) {
$this -> columns = $cols ;
return $this ;
}
public function data ( $data ) {
$this -> data = $data ;
return $this ;
}
private function evaluate ( $d , $key ) {
2013-05-14 13:55:30 +00:00
if ( count ( $this -> filters ) AND ! $this -> filters_added ) {
$d -> display_filters ( $this -> filters );
// So we dont keep extending our display_filters
$this -> filters_added = TRUE ;
}
2013-04-22 05:50:28 +00:00
if ( is_array ( $d ) AND isset ( $d [ $key ]))
$x = $d [ $key ];
2013-04-25 00:22:36 +00:00
2013-04-22 05:50:28 +00:00
// If the key is a method, we need to eval it
elseif ( preg_match ( '/\(/' , $key ) OR preg_match ( '/-\>/' , $key ))
eval ( " \$ x = \$ d-> $key ; " );
2013-04-25 00:22:36 +00:00
2013-04-22 05:50:28 +00:00
elseif ( preg_match ( '/^__VALUE__$/' , $key ))
$x = $d ;
2013-04-25 00:22:36 +00:00
2013-04-22 05:50:28 +00:00
else
2014-02-17 00:29:11 +00:00
$x = isset ( $d -> { $key }) ? $d -> display ( $key ) : '' ;
// We cant display array values
if ( is_array ( $x ))
$x = array_shift ( $x );
2013-04-22 05:50:28 +00:00
2013-10-08 23:24:11 +00:00
if ( isset ( $this -> prepend [ $key ]) AND $x ) {
2013-05-07 01:38:28 +00:00
foreach ( $this -> prepend [ $key ] as $act => $data ) {
switch ( $act ) {
2013-05-14 13:55:30 +00:00
case 'checkbox' : $x = sprintf ( '<label class="checkbox">%s %s</label>' , Form :: checkbox ( $data , $x , FALSE , array ( 'nocg' => TRUE )), $x ); // @todo Check those not yet checked
break ;
case 'input' :
if ( preg_match ( '/__VALUE__/' , $data [ 'key' ]))
$data [ 'key' ] = preg_replace ( '/__VALUE__/' , $x , $data [ 'key' ]);
$x = Form :: input ( $data [ 'key' ], isset ( $data [ 'values' ][ $x ]) ? $data [ 'values' ][ $x ] : '' , array ( 'placeholder' => $x , 'label' => $x ));
break ;
2013-05-07 01:38:28 +00:00
case 'url' : $x = HTML :: anchor ( $data . $x , $x );
2013-05-14 13:55:30 +00:00
break ;
2013-11-08 11:26:58 +00:00
case 'url_resolve' :
$filtermatchall = array ();
preg_match_all ( '/%(\w+)(\|.+)?(\/[lUC])?%/U' , $data , $filtermatchall );
foreach ( $filtermatchall [ 1 ] as $id => $key )
$data = str_replace ( $filtermatchall [ 0 ][ $id ], $d -> display ( $key ), $data );
$x = HTML :: anchor ( $data , $x );
break ;
default :
throw HTTP_Exception :: factory ( 501 , 'Unknown action :action' , array ( ':action' => $act ));
2013-05-07 01:38:28 +00:00
}
}
}
2013-11-20 02:26:02 +00:00
if ( isset ( $this -> postproc [ $key ]) and $x ) {
foreach ( $this -> postproc [ $key ] as $act => $data ) {
switch ( $act ) {
2014-07-18 02:37:45 +00:00
case 'yesno' :
$x = StaticList_YesNo :: get ( $x , TRUE );
break ;
2013-11-20 02:26:02 +00:00
case 'trim' :
if ( strlen ( $x ) > $data ) {
$x = sprintf ( '<abbr title="%s">%s</abbr>' , $x , substr ( $x , 0 , $data - 3 ) . str_repeat ( '.' , 3 ));
}
break ;
default :
throw HTTP_Exception :: factory ( 501 , 'Unknown action :action' , array ( ':action' => $act ));
}
}
}
2013-04-22 05:50:28 +00:00
return $x ;
}
2013-05-07 01:38:28 +00:00
public static function factory () {
return new Table ;
}
2013-05-14 13:55:30 +00:00
/**
* Apply additional display filters to the results
*/
public function filters ( $cols ) {
$this -> filters = $cols ;
return $this ;
}
public function jssort ( $table ) {
$this -> jssort = $table ;
2013-05-07 01:38:28 +00:00
return $this ;
}
public function page_items ( $num ) {
$this -> page = TRUE ;
$this -> page_rows = $num ;
return $this ;
}
public function prepend ( $cols ) {
$this -> prepend = $cols ;
return $this ;
}
2013-11-20 02:26:02 +00:00
public function postproc ( $cols ) {
$this -> postproc = $cols ;
return $this ;
}
2013-05-07 01:38:28 +00:00
private function process () {
$result = array ();
$row = 0 ;
foreach ( $this -> data as $o ) {
$row ++ ;
$c = 0 ;
2013-05-14 13:55:30 +00:00
// So our filters are added for this record.
$this -> filters_added = FALSE ;
2013-05-07 01:38:28 +00:00
// If we are HTML paging
if ( $this -> page ) {
if ( $row < $this -> po -> current_first_item ())
continue ;
elseif ( $row > $this -> po -> current_last_item ())
break ;
}
// If we are just listing page_rows items and a summary line as a result of exceeding that
if ( $this -> other_col AND $row > $this -> page_rows ) {
2013-05-14 13:55:30 +00:00
$this -> other += $this -> evaluate ( $o , $this -> other_col );
2013-05-07 01:38:28 +00:00
// Otherwise rendering our rows
} else {
foreach ( $this -> columns as $col => $label ) {
$c ++ ;
$result [ $row ][ 'val' ][ $c ] = $this -> evaluate ( $o , $col );
}
}
}
return $result ;
}
2013-05-14 13:55:30 +00:00
private function render () {
2013-05-07 01:38:28 +00:00
$output = '' ;
// If we need to page the results
if ( $this -> page ) {
$this -> po = new Pagination ( array (
'total_items' => count ( $this -> data ),
'items_per_page' => $this -> page_rows ,
));
$output .= ( string ) $this -> po ;
}
2013-05-14 13:55:30 +00:00
if ( $this -> select )
$output .= Form :: open ( $this -> select [ 'form' ]);
2013-05-07 01:38:28 +00:00
$output .= View :: factory ( 'table' )
2013-05-14 13:55:30 +00:00
-> set ( 'jssort' ,( $this -> jssort AND ! $this -> page ) ? $this -> jssort : FALSE )
2013-05-07 01:38:28 +00:00
-> set ( 'other' , $this -> other )
-> set ( 'th' , $this -> columns )
-> set ( 'td' , $this -> process ());
// Use the javascript paging
if ( $this -> jssort AND ! $this -> page ) {
Script :: factory ()
-> type ( 'stdin' )
-> data ( '
$ ( document ) . ready ( function () {
$ . extend ( $ . tablesorter . themes . bootstrap , {
// these classes are added to the table. To see other table classes available,
// look here: http://twitter.github.com/bootstrap/base-css.html#tables
table : " table table-striped " ,
header : " bootstrap-header " , // give the header a gradient background
footerRow : " " ,
footerCells : " " ,
icons : " " , // add "icon-white" to make them white; this icon class is added to the <i> in the header
sortNone : " bootstrap-icon-unsorted " ,
sortAsc : " icon-chevron-up " ,
sortDesc : " icon-chevron-down " ,
active : " " , // applied when column is sorted
hover : " " , // use custom css here - bootstrap class may not override it
filterRow : " " , // filter row class
even : " " , // odd row zebra striping
odd : " " // even row zebra striping
});
2013-05-14 13:55:30 +00:00
$ ( " #list-table'.( $this->jssort ? '-'. $this->jssort : '').' " ) . tablesorter ({
2013-05-07 01:38:28 +00:00
theme : " bootstrap " ,
widthFixed : true ,
headerTemplate : " { content} { icon} " , // Add icon for jui theme; new in v2.7!
widgets : [ " uitheme " , " stickyHeaders " , " filter " ],
2013-05-15 12:21:34 +00:00
widgetOptions : {
stickyHeaders_offset : " .navbar-fixed-top " ,
}
2013-05-07 01:38:28 +00:00
}) . tablesorterPager ({
// target the pager markup - see the HTML block below
2013-05-14 13:55:30 +00:00
container : $ ( " .pager'.( $this->jssort ? '-'. $this->jssort : '').' " ),
2013-05-07 01:38:28 +00:00
output : " { startRow} - { endRow} / { filteredRows} ( { totalRows}) " ,
fixedHeight : true ,
removeRows : false ,
cssGoto : " .gotoPage "
});
});
' );
Script :: factory ()
-> type ( 'file' )
-> data ( 'media/vendor/mottie-tablesorter/js/jquery.tablesorter.min.js' );
Script :: factory ()
-> type ( 'file' )
-> data ( 'media/vendor/mottie-tablesorter/js/jquery.tablesorter.widgets.min.js' );
Script :: factory ()
-> type ( 'file' )
-> data ( 'media/vendor/mottie-tablesorter/js/jquery.tablesorter.pager.min.js' );
Style :: factory ()
-> type ( 'file' )
-> data ( 'media/vendor/mottie-tablesorter/css/theme.bootstrap.css' );
Style :: factory ()
-> type ( 'file' )
-> data ( 'media/vendor/mottie-tablesorter/css/jquery.tablesorter.pager.css' );
2013-05-15 12:21:34 +00:00
// @todo The theme should be moved from here, but Controller_Media will need to know about admin requests for media/
Style :: factory ()
-> type ( 'file' )
-> data ( 'media/theme/baseadmin/css/custom/tablesort.css' );
2013-05-07 01:38:28 +00:00
}
2013-05-14 13:55:30 +00:00
if ( $this -> select ) {
$output .= Form :: button ( 'submit' , 'Submit' , array ( 'class' => 'btn btn-primary' , 'value' => $this -> select [ 'submit' ]));
foreach ( $this -> select [ 'hidden' ] as $k => $v )
$output .= Form :: hidden ( $k , $v );
$output .= Form :: close ();
}
2013-05-07 01:38:28 +00:00
return $output ;
}
2013-05-14 13:55:30 +00:00
public function select ( $form , $submit = '' , array $hidden = array ()) {
$this -> select [ 'form' ] = $form ;
$this -> select [ 'submit' ] = $submit ;
$this -> select [ 'hidden' ] = $hidden ;
return $this ;
}
2013-05-07 01:38:28 +00:00
// This enables us to page through many selected items
// @todo This is currently not usable, since our JS above needs to be fixed to work with tablesorter
2013-04-22 05:50:28 +00:00
public static function page ( $key ) {
// We have preference for parameters passed to the action.
if ( is_null ( $id = Request :: current () -> param ( 'id' ))) {
2013-05-07 01:38:28 +00:00
// First save our POST id data into the session, so we dont need it when going to each page
2016-08-03 05:56:14 +00:00
if ( is_array ( $this -> request -> post ( 'id' )))
2013-05-07 01:38:28 +00:00
Session :: instance () -> set ( 'page_table_view' . $key , 'id' );
2013-04-22 05:50:28 +00:00
if ( $ids = Session :: instance () -> get ( 'page_table_view' . $key )) {
$pag = new Pagination ( array (
'total_items' => count ( $ids ),
'items_per_page' => 1 ,
));
return array ( $ids [ $pag -> current_first_item () - 1 ],( string ) $pag );
}
}
// If we get here, then there is no previous data to retrieve.
return array ( $id , '' );
}
}
?>