|
1 |
package SL::Controller::Helper::Paginated;
|
|
2 |
|
|
3 |
use strict;
|
|
4 |
|
|
5 |
use Exporter qw(import);
|
|
6 |
our @EXPORT = qw(make_paginated get_paginate_spec get_current_paginate_params _save_current_paginate_params _get_models_handler_for_paginated _callback_handler_for_paginated);
|
|
7 |
|
|
8 |
my ($controller_paginate_spec, $current_page, $current_per_page);
|
|
9 |
|
|
10 |
sub make_paginated {
|
|
11 |
my ($class, %specs) = @_;
|
|
12 |
|
|
13 |
$specs{MODEL} ||= $class->_controller_name;
|
|
14 |
$specs{MODEL} =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
|
|
15 |
$specs{PER_PAGE} ||= "SL::DB::Manager::$specs{MODEL}"->default_objects_per_page;
|
|
16 |
$specs{FORM_PARAMS} ||= [ qw(page per_page) ];
|
|
17 |
$specs{ONLY} ||= [];
|
|
18 |
$specs{ONLY} = [ $specs{ONLY} ] if !ref $specs{ONLY};
|
|
19 |
|
|
20 |
$controller_paginate_spec = \%specs;
|
|
21 |
|
|
22 |
my %hook_params = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
|
|
23 |
$class->run_before('_save_current_paginate_params', %hook_params);
|
|
24 |
|
|
25 |
SL::Controller::Helper::GetModels::register_get_models_handlers(
|
|
26 |
$class,
|
|
27 |
callback => '_callback_handler_for_paginated',
|
|
28 |
get_models => '_get_models_handler_for_paginated',
|
|
29 |
ONLY => $specs{ONLY},
|
|
30 |
);
|
|
31 |
|
|
32 |
# $::lxdebug->dump(0, "CONSPEC", \%specs);
|
|
33 |
}
|
|
34 |
|
|
35 |
sub get_paginate_spec {
|
|
36 |
my ($class_or_self) = @_;
|
|
37 |
|
|
38 |
return $controller_paginate_spec;
|
|
39 |
}
|
|
40 |
|
|
41 |
sub get_current_paginate_params {
|
|
42 |
my ($self, %params) = @_;
|
|
43 |
|
|
44 |
my $spec = $self->get_paginate_spec;
|
|
45 |
|
|
46 |
$params{page} = $current_page unless defined $params{page};
|
|
47 |
$params{per_page} = $current_per_page unless defined $params{per_page};
|
|
48 |
|
|
49 |
my %paginate_params = (
|
|
50 |
page => ($params{page} * 1) || 1,
|
|
51 |
per_page => ($params{per_page} * 1) || $spec->{PER_PAGE},
|
|
52 |
);
|
|
53 |
|
|
54 |
my $calculated_params = "SL::DB::Manager::$spec->{MODEL}"->paginate(%paginate_params, args => {});
|
|
55 |
%paginate_params = (
|
|
56 |
%paginate_params,
|
|
57 |
num_pages => $calculated_params->{max},
|
|
58 |
common_pages => $calculated_params->{common},
|
|
59 |
);
|
|
60 |
|
|
61 |
# $::lxdebug->dump(0, "get_current_paginate_params: ", \%paginate_params);
|
|
62 |
|
|
63 |
return %paginate_params;
|
|
64 |
}
|
|
65 |
|
|
66 |
#
|
|
67 |
# private functions
|
|
68 |
#
|
|
69 |
|
|
70 |
sub _save_current_paginate_params {
|
|
71 |
my ($self) = @_;
|
|
72 |
|
|
73 |
my $paginate_spec = $self->get_paginate_spec;
|
|
74 |
$current_page = $::form->{ $paginate_spec->{FORM_PARAMS}->[0] } || 1;
|
|
75 |
$current_per_page = $::form->{ $paginate_spec->{FORM_PARAMS}->[1] } * 1;
|
|
76 |
|
|
77 |
# $::lxdebug->message(0, "saving current paginate params to $current_page / $current_per_page");
|
|
78 |
}
|
|
79 |
|
|
80 |
sub _callback_handler_for_paginated {
|
|
81 |
my ($self, %params) = @_;
|
|
82 |
|
|
83 |
if ($current_page) {
|
|
84 |
my $paginate_spec = $self->get_paginate_spec;
|
|
85 |
$params{ $paginate_spec->{FORM_PARAMS}->[0] } = $current_page;
|
|
86 |
$params{ $paginate_spec->{FORM_PARAMS}->[1] } = $current_per_page if $current_per_page;
|
|
87 |
}
|
|
88 |
|
|
89 |
# $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
|
|
90 |
|
|
91 |
return %params;
|
|
92 |
}
|
|
93 |
|
|
94 |
sub _get_models_handler_for_paginated {
|
|
95 |
my ($self, %params) = @_;
|
|
96 |
$params{model} ||= $self->get_paginate_spec->{MODEL};
|
|
97 |
|
|
98 |
"SL::DB::Manager::$params{model}"->paginate($self->get_current_paginate_params, args => \%params);
|
|
99 |
|
|
100 |
# $::lxdebug->dump(0, "GM handler for paginated; params nach modif:", \%params);
|
|
101 |
|
|
102 |
return %params;
|
|
103 |
}
|
|
104 |
|
|
105 |
1;
|
|
106 |
__END__
|
|
107 |
|
|
108 |
=pod
|
|
109 |
|
|
110 |
=encoding utf8
|
|
111 |
|
|
112 |
=head1 NAME
|
|
113 |
|
|
114 |
SL::Controller::Helper::Paginated - A helper for semi-automatic handling
|
|
115 |
of paginating lists of database models in a controller
|
|
116 |
|
|
117 |
=head1 SYNOPSIS
|
|
118 |
|
|
119 |
In a controller:
|
|
120 |
|
|
121 |
use SL::Controller::Helper::GetModels;
|
|
122 |
use SL::Controller::Helper::Paginated;
|
|
123 |
|
|
124 |
__PACKAGE__->make_paginated(
|
|
125 |
MODEL => 'BackgroundJobHistory',
|
|
126 |
ONLY => [ qw(list) ],
|
|
127 |
FORM_PARAMS => [ qw(page per_page) ],
|
|
128 |
);
|
|
129 |
|
|
130 |
sub action_list {
|
|
131 |
my ($self) = @_;
|
|
132 |
|
|
133 |
my $paginated_models = $self->get_models;
|
|
134 |
$self->render('controller/list', ENTRIES => $paginated_models);
|
|
135 |
}
|
|
136 |
|
|
137 |
In said template:
|
|
138 |
|
|
139 |
[% USE L %]
|
|
140 |
|
|
141 |
<table>
|
|
142 |
<thead>
|
|
143 |
<tr>
|
|
144 |
...
|
|
145 |
</tr>
|
|
146 |
</thead>
|
|
147 |
|
|
148 |
<tbody>
|
|
149 |
[% FOREACH entry = ENTRIES %]
|
|
150 |
<tr>
|
|
151 |
...
|
|
152 |
</tr>
|
|
153 |
[% END %]
|
|
154 |
</tbody>
|
|
155 |
</table>
|
|
156 |
|
|
157 |
[% L.paginate_controls %]
|
|
158 |
|
|
159 |
=head1 OVERVIEW
|
|
160 |
|
|
161 |
This specialized helper module enables controllers to display a
|
|
162 |
paginatable list of database models with as few lines as possible. It
|
|
163 |
can also be combined trivially with the L<SL::Controller::Sorted>
|
|
164 |
helper for sortable lists.
|
|
165 |
|
|
166 |
For this to work the controller has to provide the information which
|
|
167 |
indexes are eligible for paginateing etc. by a call to
|
|
168 |
L<make_paginated> at compile time.
|
|
169 |
|
|
170 |
The underlying functionality that enables the use of more than just
|
|
171 |
the paginate helper is provided by the controller helper
|
|
172 |
C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
|
|
173 |
more information on it.
|
|
174 |
|
|
175 |
A template can use the method C<paginate_controls> from the layout
|
|
176 |
helper module C<L> which renders the links for navigation between the
|
|
177 |
pages.
|
|
178 |
|
|
179 |
This module requires that the Rose model managers use their C<Paginated>
|
|
180 |
helper.
|
|
181 |
|
|
182 |
The C<Paginated> helper hooks into the controller call to the action via
|
|
183 |
a C<run_before> hook. This is done so that it can remember the paginate
|
|
184 |
parameters that were used in the current view.
|
|
185 |
|
|
186 |
=head1 PACKAGE FUNCTIONS
|
|
187 |
|
|
188 |
=over 4
|
|
189 |
|
|
190 |
=item C<make_paginated %paginate_spec>
|
|
191 |
|
|
192 |
This function must be called by a controller at compile time. It is
|
|
193 |
uesd to set the various parameters required for this helper to do its
|
|
194 |
magic.
|
|
195 |
|
|
196 |
The hash C<%paginate_spec> can include the following parameters:
|
|
197 |
|
|
198 |
=over 4
|
|
199 |
|
|
200 |
=item * C<MODEL>
|
|
201 |
|
|
202 |
Optional. A string: the name of the Rose database model that is used
|
|
203 |
as a default in certain cases. If this parameter is missing then it is
|
|
204 |
derived from the controller's package (e.g. for the controller
|
|
205 |
C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
|
|
206 |
C<BackgroundJobHistory>).
|
|
207 |
|
|
208 |
=item * C<PER_PAGE>
|
|
209 |
|
|
210 |
Optional. An integer: the number of models to return per page.
|
|
211 |
|
|
212 |
Defaults to the underlying database model's default number of models
|
|
213 |
per page.
|
|
214 |
|
|
215 |
=item * C<FORM_PARAMS>
|
|
216 |
|
|
217 |
Optional. An array reference with exactly two strings that name the
|
|
218 |
indexes in C<$::form> in which the current page's number (the first
|
|
219 |
element in the array) and the number of models per page (the second
|
|
220 |
element in the array) are stored.
|
|
221 |
|
|
222 |
Defaults to the values C<page> and C<per_page> if missing.
|
|
223 |
|
|
224 |
=item * C<ONLY>
|
|
225 |
|
|
226 |
Optional. An array reference containing a list of action names for
|
|
227 |
which the paginate parameters should be saved. If missing or empty then
|
|
228 |
all actions invoked on the controller are monitored.
|
|
229 |
|
|
230 |
=back
|
|
231 |
|
|
232 |
=back
|
|
233 |
|
|
234 |
=head1 INSTANCE FUNCTIONS
|
|
235 |
|
|
236 |
These functions are called on a controller instance.
|
|
237 |
|
|
238 |
=over 4
|
|
239 |
|
|
240 |
=item C<get_paginate_spec>
|
|
241 |
|
|
242 |
Returns a hash containing the currently active paginate
|
|
243 |
parameters. The following keys are returned:
|
|
244 |
|
|
245 |
=over 4
|
|
246 |
|
|
247 |
=item * C<page>
|
|
248 |
|
|
249 |
The currently active page number (numbering starts at 1).
|
|
250 |
|
|
251 |
=item * C<per_page>
|
|
252 |
|
|
253 |
Number of models per page (at least 1).
|
|
254 |
|
|
255 |
=item * C<num_pages>
|
|
256 |
|
|
257 |
Number of pages to display (at least 1).
|
|
258 |
|
|
259 |
=item * C<common_pages>
|
|
260 |
|
|
261 |
An array reference with one hash reference for each possible
|
|
262 |
page. Each hash ref contains the keys C<active> (C<1> if that page is
|
|
263 |
the currently active page), C<page> (the page number this hash
|
|
264 |
reference describes) and C<visible> (whether or not it should be
|
|
265 |
displayed).
|
|
266 |
|
|
267 |
=back
|
|
268 |
|
|
269 |
=item C<get_current_paginate_params>
|
|
270 |
|
|
271 |
Returns a hash reference to the paginate spec structure given in the call
|
|
272 |
to L<make_paginated> after normalization (hash reference construction,
|
|
273 |
applying default parameters etc).
|
|
274 |
|
|
275 |
=back
|
|
276 |
|
|
277 |
=head1 BUGS
|
|
278 |
|
|
279 |
Nothing here yet.
|
|
280 |
|
|
281 |
=head1 AUTHOR
|
|
282 |
|
|
283 |
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
|
|
284 |
|
|
285 |
=cut
|
Controller-Helfer zum Paginaten von Listen