1 package SL::Controller::Helper::Paginated;
 
   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);
 
   8 use constant PRIV => '__paginatedhelper_priv';
 
  10 my $controller_paginate_spec;
 
  13   my ($class, %specs)       = @_;
 
  15   $specs{MODEL}           ||=  $class->controller_name;
 
  16   $specs{MODEL}             =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
 
  17   $specs{PER_PAGE}        ||= "SL::DB::Manager::$specs{MODEL}"->default_objects_per_page;
 
  18   $specs{FORM_PARAMS}     ||= [ qw(page per_page) ];
 
  20   $specs{ONLY}              = [ $specs{ONLY} ] if !ref $specs{ONLY};
 
  22   $controller_paginate_spec = \%specs;
 
  24   my %hook_params           = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
 
  25   $class->run_before('_save_current_paginate_params', %hook_params);
 
  27   SL::Controller::Helper::GetModels::register_get_models_handlers(
 
  29     callback   => '_callback_handler_for_paginated',
 
  30     get_models => '_get_models_handler_for_paginated',
 
  34   # $::lxdebug->dump(0, "CONSPEC", \%specs);
 
  37 sub get_paginate_spec {
 
  38   my ($class_or_self) = @_;
 
  40   return $controller_paginate_spec;
 
  43 sub get_current_paginate_params {
 
  44   my ($self, %params)   = @_;
 
  46   my $spec              = $self->get_paginate_spec;
 
  48   my $priv              = $self->{PRIV()} || {};
 
  49   $params{page}         = $priv->{page}     unless defined $params{page};
 
  50   $params{per_page}     = $priv->{per_page} unless defined $params{per_page};
 
  52   my %paginate_params   =  (
 
  53     page                => ($params{page}     * 1) || 1,
 
  54     per_page            => ($params{per_page} * 1) || $spec->{PER_PAGE},
 
  57   my $calculated_params = "SL::DB::Manager::$spec->{MODEL}"->paginate(%paginate_params, args => {});
 
  60     num_pages    => $calculated_params->{max},
 
  61     common_pages => $calculated_params->{common},
 
  64   # $::lxdebug->dump(0, "get_current_paginate_params: ", \%paginate_params);
 
  66   return %paginate_params;
 
  73 sub _save_current_paginate_params {
 
  76   my $paginate_spec = $self->get_paginate_spec;
 
  78     page            => $::form->{ $paginate_spec->{FORM_PARAMS}->[0] } || 1,
 
  79     per_page        => $::form->{ $paginate_spec->{FORM_PARAMS}->[1] } * 1,
 
  82   # $::lxdebug->message(0, "saving current paginate params to " . $self->{PRIV()}->{page} . ' / ' . $self->{PRIV()}->{per_page});
 
  85 sub _callback_handler_for_paginated {
 
  86   my ($self, %params) = @_;
 
  87   my $priv            = $self->{PRIV()} || {};
 
  90     my $paginate_spec                             = $self->get_paginate_spec;
 
  91     $params{ $paginate_spec->{FORM_PARAMS}->[0] } = $priv->{page};
 
  92     $params{ $paginate_spec->{FORM_PARAMS}->[1] } = $priv->{per_page} if $priv->{per_page};
 
  95   # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
 
 100 sub _get_models_handler_for_paginated {
 
 101   my ($self, %params)    = @_;
 
 102   $params{model}       ||= $self->get_paginate_spec->{MODEL};
 
 104   "SL::DB::Manager::$params{model}"->paginate($self->get_current_paginate_params, args => \%params);
 
 106   # $::lxdebug->dump(0, "GM handler for paginated; params nach modif:", \%params);
 
 120 SL::Controller::Helper::Paginated - A helper for semi-automatic handling
 
 121 of paginating lists of database models in a controller
 
 127   use SL::Controller::Helper::GetModels;
 
 128   use SL::Controller::Helper::Paginated;
 
 130   __PACKAGE__->make_paginated(
 
 131     MODEL       => 'BackgroundJobHistory',
 
 132     ONLY        => [ qw(list) ],
 
 133     FORM_PARAMS => [ qw(page per_page) ],
 
 139     my $paginated_models = $self->get_models;
 
 140     $self->render('controller/list', ENTRIES => $paginated_models);
 
 155     [% FOREACH entry = ENTRIES %]
 
 163   [% L.paginate_controls %]
 
 167 This specialized helper module enables controllers to display a
 
 168 paginatable list of database models with as few lines as possible. It
 
 169 can also be combined trivially with the L<SL::Controller::Sorted>
 
 170 helper for sortable lists.
 
 172 For this to work the controller has to provide the information which
 
 173 indexes are eligible for paginateing etc. by a call to
 
 174 L<make_paginated> at compile time.
 
 176 The underlying functionality that enables the use of more than just
 
 177 the paginate helper is provided by the controller helper
 
 178 C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
 
 179 more information on it.
 
 181 A template can use the method C<paginate_controls> from the layout
 
 182 helper module C<L> which renders the links for navigation between the
 
 185 This module requires that the Rose model managers use their C<Paginated>
 
 188 The C<Paginated> helper hooks into the controller call to the action via
 
 189 a C<run_before> hook. This is done so that it can remember the paginate
 
 190 parameters that were used in the current view.
 
 192 =head1 PACKAGE FUNCTIONS
 
 196 =item C<make_paginated %paginate_spec>
 
 198 This function must be called by a controller at compile time. It is
 
 199 uesd to set the various parameters required for this helper to do its
 
 202 The hash C<%paginate_spec> can include the following parameters:
 
 208 Optional. A string: the name of the Rose database model that is used
 
 209 as a default in certain cases. If this parameter is missing then it is
 
 210 derived from the controller's package (e.g. for the controller
 
 211 C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
 
 212 C<BackgroundJobHistory>).
 
 216 Optional. An integer: the number of models to return per page.
 
 218 Defaults to the underlying database model's default number of models
 
 221 =item * C<FORM_PARAMS>
 
 223 Optional. An array reference with exactly two strings that name the
 
 224 indexes in C<$::form> in which the current page's number (the first
 
 225 element in the array) and the number of models per page (the second
 
 226 element in the array) are stored.
 
 228 Defaults to the values C<page> and C<per_page> if missing.
 
 232 Optional. An array reference containing a list of action names for
 
 233 which the paginate parameters should be saved. If missing or empty then
 
 234 all actions invoked on the controller are monitored.
 
 240 =head1 INSTANCE FUNCTIONS
 
 242 These functions are called on a controller instance.
 
 246 =item C<get_paginate_spec>
 
 248 Returns a hash containing the currently active paginate
 
 249 parameters. The following keys are returned:
 
 255 The currently active page number (numbering starts at 1).
 
 259 Number of models per page (at least 1).
 
 263 Number of pages to display (at least 1).
 
 265 =item * C<common_pages>
 
 267 An array reference with one hash reference for each possible
 
 268 page. Each hash ref contains the keys C<active> (C<1> if that page is
 
 269 the currently active page), C<page> (the page number this hash
 
 270 reference describes) and C<visible> (whether or not it should be
 
 275 =item C<get_current_paginate_params>
 
 277 Returns a hash reference to the paginate spec structure given in the call
 
 278 to L<make_paginated> after normalization (hash reference construction,
 
 279 applying default parameters etc).
 
 289 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>