Tina MVC Pagination and HTML Table Helpers

The Pagination Helper is used to format SQL results and make a sortable, paginated HTML table of results. It is based on code found at http://www.catchmyfame.com/2007/07/28/finally-the-simple-pagination-class/

There are five sample files in ‘tina-mvc/sample_apps’ which illustrate their use:

  • sample_pagination_page.php
  • sample_html_table_helper_page.php

The Pagination Helper

Create a page controller (or look for a sample controller in the sample_apps folder). This is the code that makes things happen:

 
        /**
         * Include the helper
         */
        tina_mvc_include_helper('tina_mvc_pagination_helper');
 
        /**
         * We are using custom SQL here to demonstrate the use of the pager.
         *
         * The $base_sql is a properly escaped statement that will get you all the rows you want. ORDER BY and LIMIT clauses
         * are not set - they will be set automatically.
         */
        $base_sql = 'SELECT ID AS `Database ID`, user_login AS `User Login`, display_name AS `Display Name` FROM '.$wpdb->users;
 
        /**
         * A SQL statement to get the total number of rows returned in the above statement.
         */
        $count_sql = 'SELECT COUNT(ID) FROM '.$wpdb->users;
 
        /**
         * The HTML table ID is set from the parameter you pass to the constructor
         */
        $P = new tina_mvc_pagination_helper( 'user_list' );
 
        $P->set_count_from_sql( $count_sql );
 
        /**
         * The url required to get to the default table view
         * 
         * Extra strings will be appended to this to support pagination and sorting
         */
        $P->set_base_url( tina_mvc_make_controller_url('sample-pagination') );
 
        $P->set_base_sql( $base_sql );
 
        /**
         * For the pagination links
         * 
         * This will likely be changed to an object method in the future
         */
        $P->mid_range = 9;
 
        $P->set_items_per_page( 10 );
 
        /**
         * Optional, but you probably don't want data sorted by an ID field
         */
        $P->set_default_sort_by( 'User Login' );
        $P->set_default_sort_order( 'desc' );
 
        /**
         * Grab the HTML. This is all ready to pass to your view file
         */
        $this->set_post_content( $P->get_html() );
 
        $this->set_post_title('Pagination');

You should end up with something that looks like this (this is for illustrative purposes – the column heading links used to sort rows do not work):

« Previous 1 2 3 4 5 6 7 8 999 Next »
All 

Database ID User Login Display Name
1 admin Rose
624 AlanBennett Alan
200 AlanCarr Alan
171 AlanJenkins Alan
666 AlanMartin Alan
215 AlanMatthews Alan
580 AlanPalmer Alan
125 AlanRuiz Alan
264 AlanSchmidt Alan
618 AlanWoods Alan

« Previous 1 2 3 4 5 6 7 8 999 Next »
All

The HTML Table Helper

The Pagination Helper uses the HTML table helper internally. See sample_html_table_helper_page.php in the sample_apps folder.

The table headings are taken from the array keys or object variables of whatever data you pass to the table object.

 
        /**
         * Include the helper
         */
        tina_mvc_include_helper('tina_mvc_table_helper');
 
        /**
         * The parameter is used to create a unique ID tag for the html table element.
         */
        $table = new tina_mvc_table_helper( 'my_table_table' );
 
        /**
         * $table_data is an array or an object
         */
        $table->set_data( $table_data );
 
        /**
         * If you have proper pre-escaped HTML in the headers, you will want to prevent double escaping
         */
        // $table->do_not_esc_th( TRUE );
 
        /**
         * And grab your HTML
         */
        $html = $table->get_html();

The output will look the same as the table above.

More complex examples

You will usually want to do something more funky with your tabulated data. For example, if you have a list of products a user has purchased, you might want to have the product name linked to the product page.

The following example shows how to manipulate rows and customise output. It is based on code in the the sample_pagination_3_page.php file in the sample_apps folder.

First, set up your paginator following the example above. However before calling $P->get_html() use $P->get_sql_rows() to retrieve an array of rows (as retrieved from the database using the $wpdb object.

        $rows = $P->get_sql_rows();
 
        /**
         * Want a look? ;-)
         */
        //echo "<pre>"; var_dump( $rows ); die;
 
        /**
         * Iterate throught the results and build some HTML. Note we are assigning $r by reference
         */
        foreach( $rows AS $i => & $r ) {
 
            if( $i % 2 ) {
                $bg = '#333';
                $fg = '#ccc';
            }
            else {
                $bg = '#ccc';
                $fg = '#333';
            }
 
            $r->{'Database ID'} = '<span style="color:'.$fg.';background:'.$bg.'">'.$wpdb->escape($r->{'Database ID'}).'</span>';
            $r->{'User Login'} = '<span style="color:'.$fg.';background:'.$bg.'"><a href="#" title="'.$wpdb->escape($r->{'Display Name'}).'">'.$r->{'User Login'}.'</a></span>';
 
            /**
             * You can also unset() an entry here. This has the effect of removing a row from final output.
             * You will still be able to filter results on the field though.
             */
            unset( $r->{'Display Name'} );
 
            /**
             * Add a made up field.
             */
            $r->{'A number between 1 and 10'} = rand( 1, 10);
 
        }
 
        /**
         * Set the rows, overriding the use of the html table helper
         */
        $P->set_html_rows( $rows );

The trick here is to use the get_sql_rows() function of the pagination helper to return an array of row objects (the result of a SQL call).

After that you can iterate through the rows and alter the contents before using set_html_rows() to override the rows returned from the sql call.

Note the effect of unset() above. The column is removed from output.

Also there is nothing to stop you adding adding fields my simple adding another object property to the $r variable – $r->{'A number between 1 and 10'} in the example above.

The final output will look like this (again for illustration – sortable column headings do not work here):

« Previous 1 2 3 4 5 6 7 8 9100 » Next

(show all 992)

Database ID User Login A number between 1 and 10
1 admin 1
624 AlanBennett 10
200 AlanCarr 7
171 AlanJenkins 6
666 AlanMartin 6
215 AlanMatthews 10
580 AlanPalmer 2
125 AlanRuiz 4
264 AlanSchmidt 5
618 AlanWoods 9

« Previous 1 2 3 4 5 6 7 8 9100 » Next

(show all 992)

How to suppress sortable rows for one or more columns (fixing the deliberate error above)

If you follow the example above, you may notice that the ‘A number between 1 and 10′ cannot be sorted by clicking on the column heading. If you try you’ll get a (rather ugly) error message as follows:

Tina MVC Error

Unknown column 'A number between 1 and 10' in 'order clause' // Query: SELECT ID AS `Database ID`, user_login AS `User Login`, display_name AS `Display Name` FROM wp_users ORDER BY `A number between 1 and 10` ASC LIMIT 0,10

This is pretty obvious – the field ‘A number between 1 and 10′ does not exist in the database and therefore rows cannot be sorted according to that field. (Sorting is done in SQL.)

The solution is to stop the pagination helper from adding HTML and producing a clickable column heading. This is done as follows:

        /**
         * This will prevent the helper from adding sortable column HTML to the
         * column heading 'A number between 1 and 10'.
         *
         * You cannot sort on columns that do not come directly from the database.
         */
        $P->suppress_sort( array('A number between 1 and 10') );

The suppress_sort() function accepts an array of column names. The default is to suppress sort from all columns.

Here’s what you get:

« Previous 1 2 3 4 5 6 7 8 9100 » Next

(show all 992)

Database ID User Login A number between 1 and 10
1 admin 4
624 AlanBennett 3
200 AlanCarr 1
171 AlanJenkins 9
666 AlanMartin 9
215 AlanMatthews 2
580 AlanPalmer 1
125 AlanRuiz 3
264 AlanSchmidt 3
618 AlanWoods 5

« Previous 1 2 3 4 5 6 7 8 9100 » Next

(show all 992)

Adding a search box and filtering results

As long as you search on SQL field names, you can add a filter box to your pager. Use the filter_box_on_fields() function as follows:

        /**
         * Set up the filter.
         *
         * This allows a user to search on various fields (even if they are not
         * selected for display). This will output a form at the top of the table
         * of results.
         * 
         * Parameter is array ( 'Display Name' => 'mysql_field_name' )
         */
 
        $P->filter_box_on_fields( array(
                                        'Login' => 'user_login',
                                        'Display Name' => 'display_name',
                                        'Email' => 'user_email'
                                        )
                                 );

The output is something like this:

Filter by Login, Display Name, Email:

1 2 (show all 17)

Database ID User Login A number between 1 and 10
1 admin 4
263 BonnieRose 5
497 DonnaRose 1
162 DorothyRose 4
671 GlennRose 8
258 JimmyRose 8
398 KathyRose 6
805 LeslieRose 1
146 RoseClark 4
424 RoseCruz 7

1 2 (show all 17)

Further reading

There are four files in the sample_apps folder that you can dive into. If you get stuck, just shout.

Enjoy,
Fran.

Leave a Reply