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