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