1 package SL::Controller::Helper::GetModels::Paginated;
 
   4 use parent 'SL::Controller::Helper::GetModels::Base';
 
   6 use List::Util qw(min);
 
   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) ],
 
  14   my ($self, %specs)               = @_;
 
  16   $self->set_get_models(delete $specs{get_models});
 
  17   $self->SUPER::init(%specs);
 
  19   $self->per_page($self->get_models->manager->default_objects_per_page) unless $self->per_page;
 
  21   $self->get_models->register_handlers(
 
  22     callback   => sub { shift; $self->_callback_handler_for_paginated(@_) },
 
  23     get_models => sub { shift; $self->_get_models_handler_for_paginated(@_) },
 
  26   # $::lxdebug->dump(0, "CONSPEC", \%specs);
 
  30   my ($self, %params)      = @_;
 
  32   return %{ $self->form_data } if $self->form_data;
 
  33   my $source = $self->get_models->source;
 
  36     page            => $source->{ $self->form_params->[0] } || 1,
 
  37     per_page        => $source->{ $self->form_params->[1] } * 1,
 
  40 #  my $priv              = _priv($self);
 
  41   $params{page}         = $from_form->{page}     unless defined $params{page};
 
  42   $params{per_page}     = $from_form->{per_page} unless defined $params{per_page};
 
  44   $params{page}         = ($params{page} * 1) || 1;
 
  45   $params{per_page}     = ($params{per_page} * 1) || $self->per_page;
 
  47   $self->form_data(\%params);
 
  53   my ($self, %args)   = @_;
 
  54 #  return () unless $self->is_enabled;
 
  55   my %paginate_params = $self->read_params;
 
  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() } }
 
  65   %args = $self->merge_args(\%args, \%paginate_args);
 
  67   my $calculated_params = $self->get_models->manager->paginate(%paginate_params, args => \%args);
 
  69   $self->paginated_args(\%args);
 
  70   $self->calculated_params($calculated_params);
 
  75 sub get_current_paginate_params {
 
  76   my ($self, %args)   = @_;
 
  77   return () unless $self->is_enabled;
 
  78   %{ $self->calculated_params };
 
  85 sub _callback_handler_for_paginated {
 
  86   my ($self, %params) = @_;
 
  87   my %form_params = $self->read_params;
 
  89   if ($self->is_enabled && $form_params{page}) {
 
  90     $params{ $self->form_params->[0] } = $form_params{page};
 
  91     $params{ $self->form_params->[1] } = $form_params{per_page} if $form_params{per_page};
 
  94   # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
 
  99 sub init_form_params {
 
 100   [ qw(page per_page) ]
 
 103 sub init_paginate_args {
 
 116 SL::Controller::Helper::Paginated - A helper for semi-automatic handling
 
 117 of paginating lists of database models in a controller
 
 123   use SL::Controller::Helper::GetModels;
 
 124   use SL::Controller::Helper::Paginated;
 
 126   __PACKAGE__->make_paginated(
 
 127     MODEL       => 'BackgroundJobHistory',
 
 128     ONLY        => [ qw(list) ],
 
 129     FORM_PARAMS => [ qw(page per_page) ],
 
 135     my $paginated_models = $self->get_models;
 
 136     $self->render('controller/list', ENTRIES => $paginated_models);
 
 151     [% FOREACH entry = ENTRIES %]
 
 159   [% L.paginate_controls %]
 
 163 This specialized helper module enables controllers to display a
 
 164 paginatable list of database models with as few lines as possible. It
 
 165 can also be combined trivially with the L<SL::Controller::Sorted>
 
 166 helper for sortable lists.
 
 168 For this to work the controller has to provide the information which
 
 169 indexes are eligible for paginateing etc. by a call to
 
 170 L<make_paginated> at compile time.
 
 172 The underlying functionality that enables the use of more than just
 
 173 the paginate helper is provided by the controller helper
 
 174 C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
 
 175 more information on it.
 
 177 A template can use the method C<paginate_controls> from the layout
 
 178 helper module C<L> which renders the links for navigation between the
 
 181 This module requires that the Rose model managers use their C<Paginated>
 
 184 The C<Paginated> helper hooks into the controller call to the action via
 
 185 a C<run_before> hook. This is done so that it can remember the paginate
 
 186 parameters that were used in the current view.
 
 188 =head1 PACKAGE FUNCTIONS
 
 192 =item C<make_paginated %paginate_spec>
 
 194 This function must be called by a controller at compile time. It is
 
 195 uesd to set the various parameters required for this helper to do its
 
 198 The hash C<%paginate_spec> can include the following parameters:
 
 204 Optional. A string: the name of the Rose database model that is used
 
 205 as a default in certain cases. If this parameter is missing then it is
 
 206 derived from the controller's package (e.g. for the controller
 
 207 C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
 
 208 C<BackgroundJobHistory>).
 
 210 =item * C<PAGINATE_ARGS>
 
 212 Optional. Either a code reference or the name of function to be called
 
 213 on the controller importing this helper.
 
 215 If this funciton is given then the paginate helper calls it whenever
 
 216 it has to count the total number of models for calculating the number
 
 217 of pages to display. The function must return a hash reference with
 
 218 elements suitable for passing to a Rose model manager's C<get_all>
 
 221 This can be used e.g. when filtering is used.
 
 225 Optional. An integer: the number of models to return per page.
 
 227 Defaults to the underlying database model's default number of models
 
 230 =item * C<FORM_PARAMS>
 
 232 Optional. An array reference with exactly two strings that name the
 
 233 indexes in C<$::form> in which the current page's number (the first
 
 234 element in the array) and the number of models per page (the second
 
 235 element in the array) are stored.
 
 237 Defaults to the values C<page> and C<per_page> if missing.
 
 241 Optional. An array reference containing a list of action names for
 
 242 which the paginate parameters should be saved. If missing or empty then
 
 243 all actions invoked on the controller are monitored.
 
 249 =head1 INSTANCE FUNCTIONS
 
 251 These functions are called on a controller instance.
 
 255 =item C<get_paginate_spec>
 
 257 Returns a hash containing the currently active paginate
 
 258 parameters. The following keys are returned:
 
 264 The currently active page number (numbering starts at 1).
 
 268 Number of models per page (at least 1).
 
 272 Number of pages to display (at least 1).
 
 274 =item * C<common_pages>
 
 276 An array reference with one hash reference for each possible
 
 277 page. Each hash ref contains the keys C<active> (C<1> if that page is
 
 278 the currently active page), C<page> (the page number this hash
 
 279 reference describes) and C<visible> (whether or not it should be
 
 284 =item C<get_current_paginate_params>
 
 286 Returns a hash reference to the paginate spec structure given in the call
 
 287 to L<make_paginated> after normalization (hash reference construction,
 
 288 applying default parameters etc).
 
 290 =item C<disable_pagination>
 
 292 Disable pagination for the duration of the current action. Can be used
 
 293 when using the attribute C<ONLY> to L<make_paginated> does not
 
 304 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>