File Coverage

blib/lib/Apache/Voodoo/Pager.pm
Criterion Covered Total %
statement 17 72 23.6
branch 5 28 17.8
condition 5 19 26.3
subroutine 4 5 80.0
pod 1 3 33.3
total 32 127 25.2


line stmt bran cond sub pod time code
1             =pod #####################################################################################
2              
3             =head1 NAME
4              
5             Apache::Voodoo::Pager - Provides generic pagination controls
6              
7             =head1 SYNOPSIS
8              
9             This module generates all the necessary 'next', 'previous' and page number links
10             typically found on any search engine results page. This module can be used in
11             any scenario where data must be paginated.
12              
13             my $pager = Apache::Voodoo::Pager->new(
14             'count' => 25,
15             'window' => 10,
16             'limit' => 500,
17             'persist' => [ 'url_param', ... ]
18             );
19              
20             $pager->set_configuration(
21             'count' => 40,
22             'window' => 10,
23             'limit' => 500,
24             'persist' => [ 'url_param', ... ]
25             );
26              
27             my $template_params = $pager->paginate($all_url_params,$number_of_rows_in_results);
28              
29             =cut ################################################################################
30             package Apache::Voodoo::Pager;
31              
32             $VERSION = "3.0200";
33              
34 2     2   2590 use strict;
  2         29  
  2         91  
35 2     2   2037 use POSIX qw(ceil);
  2         15235  
  2         16  
36              
37             sub new {
38 2     2 0 4 my $class = shift;
39 2         3 my $self = {};
40 2         5 bless $self, $class;
41              
42 2         7 $self->set_configuration(@_);
43              
44 2         6 return $self;
45             }
46              
47             sub set_configuration {
48 4     4 0 6 my $self = shift;
49 4         9 my %c = @_;
50              
51 4 100 66     29 $self->{'count'} = (defined($c{'count'}) && $c{'count'} =~ /^\d+$/)?$c{'count'} :25;
52 4 100 66     23 $self->{'window'} = (defined($c{'window'}) && $c{'window'} =~ /^\d+$/)?$c{'window'} :10;
53 4 50 33     16 $self->{'limit'} = (defined($c{'limit'}) && $c{'limit'} =~ /^\d+$/)?$c{'limit'} :500;
54              
55 4         11 $self->{'persist'} = $c{'persist'};
56             }
57              
58             sub paginate {
59 0     0 1   my $self = shift;
60              
61 0           my $params = shift;
62 0           my $res_count = shift;
63              
64 0           $params->{'count'} =~ s/\D//g;
65 0           $params->{'page'} =~ s/\D//g;
66 0           $params->{'showall'} =~ s/\D//g;
67              
68 0   0       my $count = $params->{'count'} || $self->{'count'};
69 0   0       my $page = $params->{'page'} || 1;
70 0   0       my $showall = $params->{'showall'} || 0;
71              
72 0           my %output;
73              
74 0 0         if ($res_count > $count) {
75 0           my $url_params = "count=$count&" . join('&', map { $_ .'='. $params->{$_} } @{$self->{'persist'}});
  0            
  0            
76              
77 0           $output{'MODE_PARAMS'} = $url_params;
78              
79 0           $output{'HAS_MORE'} = 1;
80              
81 0 0 0       if ($res_count < $self->{'limit'} && $showall) {
82 0           $output{'SHOW_MODE'} = 1;
83 0           $output{'SHOW_ALL'} = 1;
84 0           $output{'MODE_PARAMS'} .= "&showall=0";
85             }
86             else {
87 0 0         if ($res_count < $self->{'limit'}) {
88 0           $output{'MODE_PARAMS'} .= "&showall=1";
89 0           $output{'SHOW_MODE'} = 1;
90             }
91              
92             # setup the page list
93 0           my $numpages = ceil($res_count / $count);
94 0           $output{'PAGE_NUMBER'} = $page;
95 0           $output{'NUMBER_PAGES'} = $numpages;
96              
97 0 0         if ($numpages > 1) {
98             # setup sliding window of page numbers
99 0           my $start = 0;
100 0           my $window = $self->{'window'};
101 0           my $end = $window;
102              
103 0 0         if ($page >= $window) {
104 0           $end = $page + ceil($window / 2) - 1;
105              
106 0           $start = $end - $window;
107             }
108              
109 0 0         if ($end > $numpages) {
110 0           $end = $numpages;
111             }
112              
113 0           $output{'PAGES'} = [];
114 0           for (my $x = $start; $x < $end; $x++) {
115             # Put the page info into the array
116 0 0         push(@{$output{'PAGES'}},
  0            
117             {
118             'NOT_ME' => (($x + 1) == $page)?0:1,
119             'PAGE' => ($x + 1),
120             'NOT_LAST' => 1,
121             'URL_PARAMS' => $url_params . '&page='. ($x + 1)
122             }
123             );
124             }
125              
126             # prevent access of index -1 if the page number requested is beyond the range.
127 0 0         if ($#{$output{'PAGES'}} >= 0) {
  0            
128             # set the last page to last
129 0           $output{'PAGES'}->[$#{$output{'PAGES'}}]->{'NOT_LAST'} = 0;
  0            
130             }
131              
132             # setup the 'more link'
133 0 0         if ($end != $numpages) {
134 0           $output{'MORE_URL_PARAMS'} = $url_params . '&page=' . ($end + 1);
135 0           $output{'MORE_PAGE'} = $end+1;
136             }
137              
138             # setup the preivous link
139 0 0         if ($page > 1) {
140 0           $output{'HAS_PREVIOUS'} = 1;
141 0           $output{'PREVIOUS_URL_PARAMS'} = $url_params . '&page=' . ($page - 1);
142 0           $output{'PREV_PAGE'} = $page-1;
143             }
144              
145             # setup the next link
146 0 0         if ($page * $count < $res_count) {
147 0           $output{'HAS_NEXT'} = 1;
148 0           $output{'NEXT_URL_PARAMS'} = $url_params . '&page=' . ($page + 1);
149 0           $output{'NEXT_PAGE'} = $page+1;
150             }
151             }
152             }
153             }
154              
155 0           return %output;
156             }
157              
158             1;
159              
160             =pod ################################################################################
161              
162             =head1 PARAMETERS
163              
164             =over 4
165              
166             =item count
167              
168             Number of items per page
169              
170             =item window
171              
172             Number of page numbers to appear at once. window => 10 would yield links for page numbers 1 -> 10
173              
174             =item limit
175              
176             Maximum number of rows in the result that can be displayed at once. In other words
177             if limit is set to 100 and the result set contains 101 items, then the 'Show all' link will
178             be disabled.
179              
180             =item persist
181              
182             List of url parameters that should appear in every link generated by this module.
183             search parameters, sort options, etc, etc.
184              
185             =back
186              
187             =head1 METHODS
188              
189             =over 4
190              
191             =item paginate()
192              
193             returns a hashref suitable for passing to L using the example template below.
194             The entire set of url paramaters is required so that Apache::Voodoo::Pager can get access to it's own
195             parameters as well as those listed in the persist => [] configuration parameter.
196              
197             Apache::Voodoo::Pager uses two internal paramaters, 'page' and 'showall' to keep track of internal state.
198             page is the page number of the currently displayed result set (1 origin indexed) and
199             showall is set to 1 when the entire result set is being displayed at once. These values can
200             be used by the caller to determine how to properly cut the result set.
201              
202             =back
203              
204             =head1 VOODOO EXAMPLE
205              
206             use Apache::Voodoo::Pager;
207              
208             sub init {
209             my $self = shift;
210              
211             $self->{'pager'} = Apache::Voodoo::Pager->new(
212             'count' => 10,
213             'window' => 5,
214             'limit' => 100,
215             'perisist' => [ 'value' ]
216             );
217             }
218              
219             sub list {
220             my $self = shift;
221             my $p = shift;
222              
223             my $params = $p->{'params'};
224             my $dbh = $p->{'dbh'};
225              
226             my $value = $params->{'value'};
227             my $count = $params->{'count'} || 10;
228             my $page = $params->{'page'} || 1;
229             my $showall = $params->{'showall'} || 0;
230              
231             # Parameter validation and other security checks omitted for brevity
232              
233             my $stmt = "SELECT SQL_CALC_FOUND_ROWS col1,col2,col3 FROM some_table WHERE col1 = ?";
234             unless ($showall) {
235             $stmt .= " LIMIT $count OFFSET ". $count * ($page-1);
236             }
237              
238             my $results = $dbh->selectall_arrayref($stmt,undef,$value);
239             my $matches = $dbh->selectall_arrayref("SELECT FOUND_ROWS()");
240              
241             my $template_stuff = $self->{'pager'}->paginate($params,$matches->[0]->[0]);
242              
243             # other stuff this method does
244             }
245              
246              
247             =head1 EXAMPLE HTML::Template
248              
249            
250            
251            
252            
253            
254            
255              
256             |
257            
258              
259            
260             | More...
261            
262              
263            
264            
265             Previous |
266            
267            
268             Next |
269            
270              
271            
272            
273             Show Page
274             Show All
275            
276            
277            
278            
279              
280             Page of
281              
282             =cut ###########################################################################
283              
284             ################################################################################
285             # Copyright (c) 2005-2010 Steven Edwards (maverick@smurfbane.org).
286             # All rights reserved.
287             #
288             # You may use and distribute Apache::Voodoo under the terms described in the
289             # LICENSE file include in this package. The summary is it's a legalese version
290             # of the Artistic License :)
291             #
292             ################################################################################