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(@_) },
 
  25   # $::lxdebug->dump(0, "CONSPEC", \%specs);
 
  29   my ($self, %params)      = @_;
 
  31   return %{ $self->form_data } if $self->form_data;
 
  32   my $source = $self->get_models->source;
 
  35     page            =>  $source->{ $self->form_params->[0] } || 1,
 
  36     per_page        => ($source->{ $self->form_params->[1] } // 0) * 1,
 
  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};
 
  43   $params{page}         = ($params{page} * 1) || 1;
 
  44   $params{per_page}     = ($params{per_page} * 1) || $self->per_page;
 
  46   $self->form_data(\%params);
 
  52   my ($self, %args)   = @_;
 
  54   if ($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->calculated_params($calculated_params);
 
  72   $self->paginated_args(\%args);
 
  77 sub get_current_paginate_params {
 
  78   my ($self, %args)   = @_;
 
  79   return () unless $self->is_enabled;
 
  80   %{ $self->calculated_params };
 
  87 sub _callback_handler_for_paginated {
 
  88   my ($self, %params) = @_;
 
  89   my %form_params = $self->read_params;
 
  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};
 
  96   # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
 
 101 sub init_form_params {
 
 102   [ qw(page per_page) ]
 
 105 sub init_paginate_args {
 
 118 SL::Controller::Helper::Paginated - A helper for semi-automatic handling
 
 119 of paginating lists of database models in a controller
 
 125   SL::Controller::Helper::GetModels->new(
 
 128       form_params => [ qw(page per_page) ],
 
 135   [% L.paginate_controls %]
 
 139 This C<GetModels> plugin enables controllers to display a
 
 140 paginatable list of database models with as few lines as possible.
 
 142 For this to work the controller has to provide the information which
 
 143 indexes are eligible for paginateing etc. during C<GetModels> creation.
 
 145 The underlying functionality that enables the use of more than just
 
 146 the paginate helper is provided by the controller helper
 
 147 C<GetModels>. See the documentation for L<SL::Controller::Helper::GetModels>
 
 148 for more information on it.
 
 150 A template can use the method C<paginate_controls> from the layout
 
 151 helper module C<L> which renders the links for navigation between the
 
 154 This module requires that the Rose model managers use their C<Paginated>
 
 163 Optional. The number of models to return per page.
 
 165 Defaults to the underlying database model's default number of models
 
 168 =item * C<form_params>
 
 170 Optional. An array reference with exactly two strings that name the
 
 171 indexes in C<$::form> in which the current page's number (the first
 
 172 element in the array) and the number of models per page (the second
 
 173 element in the array) are stored.
 
 175 Defaults to the values C<page> and C<per_page> if missing.
 
 179 =head1 INSTANCE FUNCTIONS
 
 181 These functions are called on a C<GetModels> instance and delegated here.
 
 185 =item C<get_paginate_spec>
 
 187 Returns a hash containing the currently active paginate
 
 188 parameters. The following keys are returned:
 
 194 The currently active page number (numbering starts at 1).
 
 198 Number of models per page (at least 1).
 
 202 Number of pages to display (at least 1).
 
 204 =item * C<common_pages>
 
 206 An array reference with one hash reference for each possible
 
 207 page. Each hash ref contains the keys C<active> (C<1> if that page is
 
 208 the currently active page), C<page> (the page number this hash
 
 209 reference describes) and C<visible> (whether or not it should be
 
 214 =item C<get_current_paginate_params>
 
 216 Returns a hash reference to the paginate spec structure given in the
 
 217 configuration after normalization (hash reference construction,
 
 218 applying default parameters etc).
 
 224 C<common_pages> generates an array with an entry for every page, which gets
 
 225 slow if there are a lot of entries. Current observation holds that up to about
 
 226 1000 pages there is no noticable slowdown, but at about 10000 it gets
 
 227 noticable. At 100k-500k pages it's takes way too long and should be remodelled.
 
 229 This case currently only applies for databases with very large amounts of parts
 
 230 that get paginated, but BackgroundJobHistory can also accumulate.
 
 234 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
 
 236 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>