Erste Version GetModels rewrite
authorSven Schöling <s.schoeling@linet-services.de>
Mon, 16 Sep 2013 17:12:50 +0000 (19:12 +0200)
committerSven Schöling <s.schoeling@linet-services.de>
Mon, 14 Oct 2013 09:56:11 +0000 (11:56 +0200)
known bugs:
disable pagination funktioniert nicht
compiletime optimizations werden noch nicht benutzt
doku fehlt

SL/Controller/DeliveryPlan.pm
SL/Controller/Helper/Filtered.pm [deleted file]
SL/Controller/Helper/GetModels.pm
SL/Controller/Helper/GetModels/Base.pm [new file with mode: 0644]
SL/Controller/Helper/GetModels/Filtered.pm [new file with mode: 0644]
SL/Controller/Helper/GetModels/Paginated.pm [new file with mode: 0644]
SL/Controller/Helper/GetModels/Sorted.pm [new file with mode: 0644]
SL/Controller/Helper/Paginated.pm [deleted file]
SL/Controller/Helper/Sorted.pm [deleted file]
SL/Template/Plugin/L.pm
templates/webpages/delivery_plan/report_bottom.html

index b8ee1c4..7d394be 100644 (file)
@@ -6,34 +6,43 @@ use parent qw(SL::Controller::Base);
 use Clone qw(clone);
 use SL::DB::OrderItem;
 use SL::Controller::Helper::GetModels;
-use SL::Controller::Helper::Paginated;
-use SL::Controller::Helper::Sorted;
-use SL::Controller::Helper::Filtered;
 use SL::Controller::Helper::ReportGenerator;
 use SL::Locale::String;
 
 use Rose::Object::MakeMethods::Generic (
   scalar => [ qw(db_args flat_filter) ],
+  'scalar --get_set_init' => [ qw(models) ],
 );
 
 __PACKAGE__->run_before(sub { $::auth->assert('sales_order_edit'); });
 
-__PACKAGE__->make_filtered(
-  MODEL             => 'OrderItem',
-  LAUNDER_TO        => 'filter'
-);
-__PACKAGE__->make_paginated(
-  MODEL         => 'OrderItem',
-  ONLY          => [ qw(list) ],
-);
-
-__PACKAGE__->make_sorted(
-  MODEL             => 'OrderItem',
-  ONLY              => [ qw(list) ],
-
-  DEFAULT_BY        => 'reqdate',
-  DEFAULT_DIR       => 1,
-
+#__PACKAGE__->make_filtered(
+#  MODEL             => 'OrderItem',
+#  LAUNDER_TO        => 'filter'
+#);
+#__PACKAGE__->make_paginated(
+#  MODEL         => 'OrderItem',
+#  ONLY          => [ qw(list) ],
+#);
+#
+#__PACKAGE__->make_sorted(
+#  MODEL             => 'OrderItem',
+#  ONLY              => [ qw(list) ],
+#
+#  DEFAULT_BY        => 'reqdate',
+#  DEFAULT_DIR       => 1,
+#
+#  reqdate           => t8('Reqdate'),
+#  description       => t8('Description'),
+#  partnumber        => t8('Part Number'),
+#  qty               => t8('Qty'),
+#  shipped_qty       => t8('shipped'),
+#  not_shipped_qty   => t8('not shipped'),
+#  ordnumber         => t8('Order'),
+#  customer          => t8('Customer'),
+#);
+
+my %sort_columns = (
   reqdate           => t8('Reqdate'),
   description       => t8('Description'),
   partnumber        => t8('Part Number'),
@@ -121,7 +130,7 @@ sub action_list {
 
   $self->make_filter_summary;
 
-  my $orderitems = $self->get_models(query => $delivery_plan_query, with_objects => [ 'order', 'order.customer', 'part' ]);
+  my $orderitems = $self->models->get;
 
   $self->prepare_report;
   $self->report_generator_list_objects(report => $self->{report}, objects => $orderitems);
@@ -149,11 +158,11 @@ sub prepare_report {
     not_shipped_qty   => {      sub => sub { $::form->format_amount(\%::myconfig, $_[0]->qty - $_[0]->shipped_qty, 2) . ' ' . $_[0]->unit } },
     ordnumber         => {      sub => sub { $_[0]->order->ordnumber                                                         },
                            obj_link => sub { $self->link_to($_[0]->order)                                                    } },
-    customer          => {      sub => sub { $_[0]->order->customer->name                                                    },
+    customer          => {      sub => sub { return ''; $_[0]->order->customer->name                                                    },
                            obj_link => sub { $self->link_to($_[0]->order->customer)                                          } },
   );
 
-  map { $column_defs{$_}->{text} = $::locale->text( $self->get_sort_spec->{$_}->{title} ) } keys %column_defs;
+  $column_defs{$_}->{text} = $sort_columns{$_} for keys %column_defs;
 
   $report->set_options(
     std_column_visibility => 1,
@@ -161,7 +170,7 @@ sub prepare_report {
     output_format         => 'HTML',
     top_info_text         => $::locale->text('Delivery Plan for currently outstanding sales orders'),
     raw_top_info_text     => $self->render('delivery_plan/report_top',    { output => 0 }),
-    raw_bottom_info_text  => $self->render('delivery_plan/report_bottom', { output => 0 }),
+    raw_bottom_info_text  => $self->render('delivery_plan/report_bottom', { output => 0 }, models => $self->models),
     title                 => $::locale->text('Delivery Plan'),
     allow_pdf_export      => 1,
     allow_csv_export      => 1,
@@ -170,9 +179,9 @@ sub prepare_report {
   $report->set_column_order(@columns);
   $report->set_export_options(qw(list filter));
   $report->set_options_from_form;
-  $self->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
+  $self->models->sorted->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
 
-  $self->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
+  $self->models->paginated->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
 }
 
 sub make_filter_summary {
@@ -209,6 +218,27 @@ sub make_filter_summary {
   $self->{filter_summary} = join ', ', @filter_strings;
 }
 
+sub init_models {
+  my ($self) = @_;
+
+  SL::Controller::Helper::GetModels->new(
+    controller => $self,
+    model  => 'OrderItem', # defaults to controller
+    filtered => {
+      launder_to => 'filter',
+    },
+    sorted => {
+      _default => {
+        by        => 'reqdate',
+        dir       => 1,
+      },
+      %sort_columns,
+    },
+    query => $delivery_plan_query,
+    with_objects => [ 'order', 'order.customer', 'part' ],
+  );
+}
+
 sub link_to {
   my ($self, $object, %params) = @_;
 
diff --git a/SL/Controller/Helper/Filtered.pm b/SL/Controller/Helper/Filtered.pm
deleted file mode 100644 (file)
index 164e5ed..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-package SL::Controller::Helper::Filtered;
-
-use strict;
-
-use Exporter qw(import);
-use SL::Controller::Helper::ParseFilter ();
-use List::MoreUtils qw(uniq);
-our @EXPORT = qw(make_filtered get_filter_spec get_current_filter_params disable_filtering _save_current_filter_params _callback_handler_for_filtered _get_models_handler_for_filtered);
-
-use constant PRIV => '__filteredhelper_priv';
-
-my %controller_filter_spec;
-
-sub make_filtered {
-  my ($class, %specs)             = @_;
-
-  $specs{MODEL}                 //=  $class->controller_name;
-  $specs{MODEL}                   =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
-  $specs{FORM_PARAMS}           //= 'filter';
-  $specs{LAUNDER_TO}              = '__INPLACE__' unless exists $specs{LAUNDER_TO};
-  $specs{ONLY}                  //= [];
-  $specs{ONLY}                    = [ $specs{ONLY} ] if !ref $specs{ONLY};
-  $specs{ONLY_MAP}                = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
-
-  $controller_filter_spec{$class} = \%specs;
-
-  my %hook_params                 = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
-  $class->run_before('_save_current_filter_params', %hook_params);
-
-  SL::Controller::Helper::GetModels::register_get_models_handlers(
-    $class,
-    callback   => '_callback_handler_for_filtered',
-    get_models => '_get_models_handler_for_filtered',
-    ONLY       => $specs{ONLY},
-  );
-
-  # $::lxdebug->dump(0, "CONSPEC", \%specs);
-}
-
-sub get_filter_spec {
-  my ($class_or_self) = @_;
-
-  return $controller_filter_spec{ref($class_or_self) || $class_or_self};
-}
-
-sub get_current_filter_params {
-  my ($self)   = @_;
-
-  return %{ _priv($self)->{filter_params} } if _priv($self)->{filter_params};
-
-  require Carp;
-  Carp::confess('It seems a GetModels plugin tries to access filter params before they got calculated. Make sure your make_filtered call comes first.');
-}
-
-sub _make_current_filter_params {
-  my ($self, %params)   = @_;
-
-  my $spec              = $self->get_filter_spec;
-  my $filter            = $params{filter} // _priv($self)->{filter} // {},
-  my %filter_args       = _get_filter_args($self, $spec);
-  my %parse_filter_args = (
-    class        => "SL::DB::Manager::$spec->{MODEL}",
-    with_objects => $params{with_objects},
-  );
-  my $laundered;
-  if ($spec->{LAUNDER_TO} eq '__INPLACE__') {
-
-  } elsif ($spec->{LAUNDER_TO}) {
-    $laundered = {};
-    $parse_filter_args{launder_to} = $laundered;
-  } else {
-    $parse_filter_args{no_launder} = 1;
-  }
-
-  my %calculated_params = SL::Controller::Helper::ParseFilter::parse_filter($filter, %parse_filter_args);
-
-  $calculated_params{query} = [
-    @{ $calculated_params{query} || [] },
-    @{ $filter_args{      query} || [] },
-    @{ $params{           query} || [] },
-  ];
-
-  $calculated_params{with_objects} = [
-    uniq
-    @{ $calculated_params{with_objects} || [] },
-    @{ $filter_args{      with_objects} || [] },
-    @{ $params{           with_objects} || [] },
-  ];
-
-  if ($laundered) {
-    if ($self->can($spec->{LAUNDER_TO})) {
-      $self->${\ $spec->{LAUNDER_TO} }($laundered);
-    } else {
-      $self->{$spec->{LAUNDER_TO}} = $laundered;
-    }
-  }
-
-  # $::lxdebug->dump(0, "get_current_filter_params: ", \%calculated_params);
-
-  _priv($self)->{filter_params} = \%calculated_params;
-
-  return %calculated_params;
-}
-
-sub disable_filtering {
-  my ($self)               = @_;
-  _priv($self)->{disabled} = 1;
-}
-
-#
-# private functions
-#
-
-sub _get_filter_args {
-  my ($self, $spec) = @_;
-
-  $spec           ||= $self->get_filter_spec;
-
-  my %filter_args   = ref($spec->{FILTER_ARGS}) eq 'CODE' ? %{ $spec->{FILTER_ARGS}->($self) }
-                    :     $spec->{FILTER_ARGS}            ? do { my $sub = $spec->{FILTER_ARGS}; %{ $self->$sub() } }
-                    :                                       ();
-}
-
-sub _save_current_filter_params {
-  my ($self)        = @_;
-
-  return if !_is_enabled($self);
-
-  my $filter_spec = $self->get_filter_spec;
-  $self->{PRIV()}{filter} = $::form->{ $filter_spec->{FORM_PARAMS} };
-
-  # $::lxdebug->message(0, "saving current filter params to " . $self->{PRIV()}->{page} . ' / ' . $self->{PRIV()}->{per_page});
-}
-
-sub _callback_handler_for_filtered {
-  my ($self, %params) = @_;
-  my $priv            = _priv($self);
-
-  if (_is_enabled($self) && $priv->{filter}) {
-    my $filter_spec = $self->get_filter_spec;
-    my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($priv->{filter}, $filter_spec->{FORM_PARAMS});
-    %params         = (%params, @$flattened);
-  }
-
-  # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
-
-  return %params;
-}
-
-sub _get_models_handler_for_filtered {
-  my ($self, %params)    = @_;
-  my $spec               = $self->get_filter_spec;
-
-  # $::lxdebug->dump(0,  "params in get_models_for_filtered", \%params);
-
-  my %filter_params;
-  %filter_params = _make_current_filter_params($self, %params)  if _is_enabled($self);
-
-  # $::lxdebug->dump(0, "GM handler for filtered; params nach modif (is_enabled? " . _is_enabled($self) . ")", \%params);
-
-  return (%params, %filter_params);
-}
-
-sub _priv {
-  my ($self)        = @_;
-  $self->{PRIV()} ||= {};
-  return $self->{PRIV()};
-}
-
-sub _is_enabled {
-  my ($self) = @_;
-  return !_priv($self)->{disabled} && ($self->get_filter_spec->{ONLY_MAP}->{$self->action_name} || $self->get_filter_spec->{ONLY_MAP}->{'__ALL__'});
-}
-
-1;
-
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Controller::Helper::Filtered - A helper for semi-automatic handling
-of filtered lists of database models in a controller
-
-=head1 SYNOPSIS
-
-In a controller:
-
-  use SL::Controller::Helper::GetModels;
-  use SL::Controller::Helper::Filtered;
-
-  __PACKAGE__->make_filter(
-    MODEL       => 'Part',
-    ONLY        => [ qw(list) ],
-    FORM_PARAMS => [ qw(filter) ],
-  );
-
-  sub action_list {
-    my ($self) = @_;
-
-    my $filtered_models = $self->get_models(%addition_filters);
-    $self->render('controller/list', ENTRIES => $filtered_models);
-  }
-
-
-=head1 OVERVIEW
-
-This helper module enables use of the L<SL::Controller::Helper::ParseFilter>
-methods in conjunction with the L<SL::Controller::Helper::GetModels> style of
-plugins. Additional filters can be defined in the database models and filtering
-can be reduced to a minimum of work.
-
-This plugin can be combined with L<SL::Controller::Sorted> and
-L<SL::Controller::Paginated> for filtered, sorted and paginated lists.
-
-The controller has to provive information where to look for filter information
-at compile time. This call is L<make_filtered>.
-
-The underlying functionality that enables the use of more than just
-the paginate helper is provided by the controller helper
-C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
-more information on it.
-
-=head1 PACKAGE FUNCTIONS
-
-=over 4
-
-=item C<make_filtered %filter_spec>
-
-This function must be called by a controller at compile time. It is
-uesd to set the various parameters required for this helper to do its
-magic.
-
-Careful: If you want to use this in conjunction with
-L<SL:Controller::Helper::Paginated>, you need to call C<make_filtered> first,
-or the paginating will not get all the relevant information to estimate the
-number of pages correctly. To ensure this does not happen, this module will
-croak when it detects such a scenario.
-
-The hash C<%filter_spec> can include the following parameters:
-
-=over 4
-
-=item * C<MODEL>
-
-Optional. A string: the name of the Rose database model that is used
-as a default in certain cases. If this parameter is missing then it is
-derived from the controller's package (e.g. for the controller
-C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
-C<BackgroundJobHistory>).
-
-=item * C<FORM_PARAMS>
-
-Optional. Indicates a key in C<$::form> to be used as filter.
-
-Defaults to the values C<filter> if missing.
-
-=item * C<LAUNDER_TO>
-
-Option. Indicates a target for laundered filter arguments in the controller.
-Can be set to C<undef> to disable laundering, and can be set to method named or
-hash keys of the controller. In the latter case the laundered structure will be
-put there.
-
-Defaults to inplace laundering which is not normally settable.
-
-=item * C<ONLY>
-
-Optional. An array reference containing a list of action names for
-which the paginate parameters should be saved. If missing or empty then
-all actions invoked on the controller are monitored.
-
-=back
-
-=back
-
-=head1 INSTANCE FUNCTIONS
-
-These functions are called on a controller instance.
-
-=over 4
-
-=item C<get_current_filter_params>
-
-Returns a hash to be used in manager C<get_all> calls or to be passed on to
-GetModels. Will only work if the get_models chain has been called at least
-once, because only then the full parameters can get parsed and stored. Will
-croak otherwise.
-
-=item C<disable_filtering>
-
-Disable filtering for the duration of the current action. Can be used
-when using the attribute C<ONLY> to L<make_filtered> does not
-cover all cases.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
-
-=cut
index 821d7a1..ae9810b 100644 (file)
@@ -2,21 +2,48 @@ package SL::Controller::Helper::GetModels;
 
 use strict;
 
-use Exporter qw(import);
-our @EXPORT = qw(get_models_url_params get_callback get_models);
+use parent 'Rose::Object';
+use SL::Controller::Helper::GetModels::Filtered;
+use SL::Controller::Helper::GetModels::Sorted;
+use SL::Controller::Helper::GetModels::Paginated;
+
+use Rose::Object::MakeMethods::Generic (
+  scalar => [ qw(controller model query with_objects filtered sorted paginated) ],
+  'scalar --get_set_init' => [ qw(handlers) ],
+);
 
 use constant PRIV => '__getmodelshelperpriv';
 
-my $registered_handlers = {};
+#my $registered_handlers = {};
+
+sub init {
+  my ($self, %params) = @_;
+
+#  for my $plugin (qw(filtered sorted paginated)) {
+#    next unless $params{$plugin};
+#    $self->${ \"make_$plugin" }(%{ delete $params{$plugin} || {} });
+#  }
+#
+  # TODO: default model
+  $self->model(delete $params{model});
+
+  for my $plugin (qw(filtered sorted paginated)) {
+    next unless my $spec = delete $params{$plugin} // {};
+    my $plugin_class = "SL::Controller::Helper::GetModels::" . ucfirst $plugin;
+    $self->$plugin($plugin_class->new(%$spec, get_models => $self));
+  }
+
+  $self->SUPER::init(%params);
+}
 
-sub register_get_models_handlers {
-  my ($class, %additional_handlers) = @_;
+sub register_handlers {
+  my ($self, %additional_handlers) = @_;
 
-  my $only        = delete($additional_handlers{ONLY}) || [];
-  $only           = [ $only ] if !ref $only;
-  my %hook_params = @{ $only } ? ( only => $only ) : ();
+#  my $only        = delete($additional_handlers{ONLY}) || [];
+#  $only           = [ $only ] if !ref $only;
+#  my %hook_params = @{ $only } ? ( only => $only ) : ();
 
-  my $handlers    = _registered_handlers($class);
+  my $handlers    = $self->handlers;
   map { push @{ $handlers->{$_} }, $additional_handlers{$_} if $additional_handlers{$_} } keys %$handlers;
 }
 
@@ -39,19 +66,34 @@ sub get_models_url_params {
 sub get_callback {
   my ($self, %override_params) = @_;
 
-  my %default_params = _run_handlers($self, 'callback', action => $self->action_name);
+  my %default_params = $self->_run_handlers('callback', action => $self->controller->action_name);
 
-  return $self->url_for(%default_params, %override_params);
+  return $self->controller->url_for(%default_params, %override_params);
 }
 
-sub get_models {
-  my ($self, %override_params) = @_;
+sub get {
+  my ($self, %params) = @_;
+
+  push @{ $params{query}        ||= [] }, @{ $self->query || [] };
+  push @{ $params{with_objects} ||= [] }, @{ $self->with_objects || [] };
+
+  %params                      = $self->_run_handlers('get_models', %params);
+
+  return $self->manager->get_all(%params);
+}
+
+sub get_paginate_args {
+  my ($self, %params) = @_;
 
-  my %params                   = _run_handlers($self, 'get_models', %override_params);
+  push @{ $params{query}        ||= [] }, @{ $self->query || [] };
+  push @{ $params{with_objects} ||= [] }, @{ $self->with_objects || [] };
 
-  my $model                    = delete($params{model}) || die "No 'model' to work on";
+  $self->paginated->get_current_paginate_params(%params);
+}
 
-  return "SL::DB::Manager::${model}"->get_all(%params);
+sub manager {
+  die "No 'model' to work on" unless $_[0]->model;
+  "SL::DB::Manager::" . $_[0]->model;
 }
 
 #
@@ -61,7 +103,7 @@ sub get_models {
 sub _run_handlers {
   my ($self, $handler_type, %params) = @_;
 
-  foreach my $sub (@{ _registered_handlers(ref $self)->{$handler_type} }) {
+  foreach my $sub (@{ $self->handlers->{$handler_type} }) {
     if (ref $sub eq 'CODE') {
       %params = $sub->($self, %params);
     } elsif ($self->can($sub)) {
@@ -74,8 +116,11 @@ sub _run_handlers {
   return %params;
 }
 
-sub _registered_handlers {
-  $registered_handlers->{$_[0]} //= { callback => [], get_models => [] }
+sub init_handlers {
+  {
+    callback => [],
+    get_models => [],
+  }
 }
 
 1;
diff --git a/SL/Controller/Helper/GetModels/Base.pm b/SL/Controller/Helper/GetModels/Base.pm
new file mode 100644 (file)
index 0000000..3d28de5
--- /dev/null
@@ -0,0 +1,29 @@
+package SL::Controller::Helper::GetModels::Base;
+
+use strict;
+use parent 'Rose::Object';
+use Scalar::Util qw(weaken);
+
+
+use Rose::Object::MakeMethods::Generic (
+  scalar => [ qw(get_models) ],
+);
+
+sub set_get_models {
+  $_[0]->get_models($_[1]);
+
+  weaken($_[1]);
+}
+
+sub merge_args {
+  my ($self, @args) = @_;
+  my $final_args = { };
+
+  for my $field (qw(query with_objects)) {
+    $final_args->{$field} = [ map { @{ $_->{$field} || [] } } @args ];
+  }
+
+  return %$final_args;
+}
+
+1;
diff --git a/SL/Controller/Helper/GetModels/Filtered.pm b/SL/Controller/Helper/GetModels/Filtered.pm
new file mode 100644 (file)
index 0000000..3374471
--- /dev/null
@@ -0,0 +1,279 @@
+package SL::Controller::Helper::GetModels::Filtered;
+
+use strict;
+use parent 'SL::Controller::Helper::GetModels::Base';
+
+use Exporter qw(import);
+use SL::Controller::Helper::ParseFilter ();
+use List::MoreUtils qw(uniq);
+
+use Rose::Object::MakeMethods::Generic (
+  scalar => [ qw(disabled filter_args filter_params) ],
+  'scalar --get_set_init' => [ qw(form_params launder_to) ],
+);
+
+sub init {
+  my ($self, %specs)             = @_;
+
+  $self->set_get_models(delete $specs{get_models});
+  $self->SUPER::init(%specs);
+
+  $self->get_models->register_handlers(
+    callback   => sub { shift; $self->_callback_handler_for_filtered(@_) },
+    get_models => sub { shift; $self->_get_models_handler_for_filtered(@_) },
+  );
+
+  # $::lxdebug->dump(0, "CONSPEC", \%specs);
+}
+
+sub get_current_filter_params {
+  my ($self)   = @_;
+
+  return $self->filter_params if $self->filter_params;
+
+  require Carp;
+  Carp::confess('It seems a GetModels plugin tries to access filter params before they got calculated. Make sure your make_filtered call comes first.');
+}
+
+sub _make_current_filter_params {
+  my ($self, %params)   = @_;
+
+#  my $spec              = $self->get_filter_spec;
+  my $filter            = $params{filter} // $::form->{ $self->form_params } // {},
+  my %filter_args       = $self->_get_filter_args;
+  my %parse_filter_args = (
+    class        => $self->get_models->manager,
+    with_objects => $params{with_objects},
+  );
+  my $laundered;
+  if ($self->launder_to eq '__INPLACE__') {
+    # nothing to do
+  } elsif ($self->launder_to) {
+    $laundered = {};
+    $parse_filter_args{launder_to} = $laundered;
+  } else {
+    $parse_filter_args{no_launder} = 1;
+  }
+
+  my %calculated_params = SL::Controller::Helper::ParseFilter::parse_filter($filter, %parse_filter_args);
+  %calculated_params = $self->merge_args(\%calculated_params, \%filter_args, \%params);
+
+#  $calculated_params{query} = [
+#    @{ $calculated_params{query} || [] },
+#    @{ $filter_args{      query} || [] },
+#    @{ $params{           query} || [] },
+#  ];
+#
+#  $calculated_params{with_objects} = [
+#    uniq
+#    @{ $calculated_params{with_objects} || [] },
+#    @{ $filter_args{      with_objects} || [] },
+#    @{ $params{           with_objects} || [] },
+#  ];
+
+  if ($laundered) {
+    if ($self->get_models->controller->can($self->launder_to)) {
+      $self->get_models->controller->${\ $self->launder_to }($laundered);
+    } else {
+      $self->get_models->controller->{$self->launder_to} = $laundered;
+    }
+  }
+
+  # $::lxdebug->dump(0, "get_current_filter_params: ", \%calculated_params);
+
+  $self->filter_params(\%calculated_params);
+
+  return %calculated_params;
+}
+
+sub disable_filtering {
+  my ($self)               = @_;
+  $self->disabled(1);
+}
+
+#
+# private functions
+#
+
+sub _get_filter_args {
+  my ($self, $spec) = @_;
+
+  my %filter_args   = ref($self->filter_args) eq 'CODE' ? %{ $self->filter_args->($self) }
+                    :     $self->filter_args            ? do { my $sub = $self->filter_args; %{ $self->get_models->controller->$sub() } }
+                    :                                       ();
+}
+
+sub _callback_handler_for_filtered {
+  my ($self, %params) = @_;
+
+  if ($self->is_enabled) {
+    my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($::form->{ $self->form_params }, $self->form_params);
+    %params         = (%params, @{ $flattened || [] });
+  }
+
+  # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
+
+  return %params;
+}
+
+sub _get_models_handler_for_filtered {
+  my ($self, %params)    = @_;
+
+  # $::lxdebug->dump(0,  "params in get_models_for_filtered", \%params);
+
+  my %filter_params;
+  %filter_params = $self->_make_current_filter_params(%params)  if $self->is_enabled;
+
+  # $::lxdebug->dump(0, "GM handler for filtered; params nach modif (is_enabled? " . $self->is_enabled . ")", \%params);
+
+  return (%params, %filter_params);
+}
+
+sub is_enabled {
+  !$_[0]->disabled;
+}
+
+sub init_form_params {
+  'filter'
+}
+
+sub init_launder_to {
+  'filter'
+}
+
+
+1;
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Controller::Helper::Filtered - A helper for semi-automatic handling
+of filtered lists of database models in a controller
+
+=head1 SYNOPSIS
+
+In a controller:
+
+  use SL::Controller::Helper::GetModels;
+  use SL::Controller::Helper::Filtered;
+
+  __PACKAGE__->make_filter(
+    MODEL       => 'Part',
+    ONLY        => [ qw(list) ],
+    FORM_PARAMS => [ qw(filter) ],
+  );
+
+  sub action_list {
+    my ($self) = @_;
+
+    my $filtered_models = $self->get_models(%addition_filters);
+    $self->render('controller/list', ENTRIES => $filtered_models);
+  }
+
+
+=head1 OVERVIEW
+
+This helper module enables use of the L<SL::Controller::Helper::ParseFilter>
+methods in conjunction with the L<SL::Controller::Helper::GetModels> style of
+plugins. Additional filters can be defined in the database models and filtering
+can be reduced to a minimum of work.
+
+This plugin can be combined with L<SL::Controller::Sorted> and
+L<SL::Controller::Paginated> for filtered, sorted and paginated lists.
+
+The controller has to provive information where to look for filter information
+at compile time. This call is L<make_filtered>.
+
+The underlying functionality that enables the use of more than just
+the paginate helper is provided by the controller helper
+C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
+more information on it.
+
+=head1 PACKAGE FUNCTIONS
+
+=over 4
+
+=item C<make_filtered %filter_spec>
+
+This function must be called by a controller at compile time. It is
+uesd to set the various parameters required for this helper to do its
+magic.
+
+Careful: If you want to use this in conjunction with
+L<SL:Controller::Helper::Paginated>, you need to call C<make_filtered> first,
+or the paginating will not get all the relevant information to estimate the
+number of pages correctly. To ensure this does not happen, this module will
+croak when it detects such a scenario.
+
+The hash C<%filter_spec> can include the following parameters:
+
+=over 4
+
+=item * C<MODEL>
+
+Optional. A string: the name of the Rose database model that is used
+as a default in certain cases. If this parameter is missing then it is
+derived from the controller's package (e.g. for the controller
+C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
+C<BackgroundJobHistory>).
+
+=item * C<FORM_PARAMS>
+
+Optional. Indicates a key in C<$::form> to be used as filter.
+
+Defaults to the values C<filter> if missing.
+
+=item * C<LAUNDER_TO>
+
+Option. Indicates a target for laundered filter arguments in the controller.
+Can be set to C<undef> to disable laundering, and can be set to method named or
+hash keys of the controller. In the latter case the laundered structure will be
+put there.
+
+Defaults to inplace laundering which is not normally settable.
+
+=item * C<ONLY>
+
+Optional. An array reference containing a list of action names for
+which the paginate parameters should be saved. If missing or empty then
+all actions invoked on the controller are monitored.
+
+=back
+
+=back
+
+=head1 INSTANCE FUNCTIONS
+
+These functions are called on a controller instance.
+
+=over 4
+
+=item C<get_current_filter_params>
+
+Returns a hash to be used in manager C<get_all> calls or to be passed on to
+GetModels. Will only work if the get_models chain has been called at least
+once, because only then the full parameters can get parsed and stored. Will
+croak otherwise.
+
+=item C<disable_filtering>
+
+Disable filtering for the duration of the current action. Can be used
+when using the attribute C<ONLY> to L<make_filtered> does not
+cover all cases.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
+
+=cut
diff --git a/SL/Controller/Helper/GetModels/Paginated.pm b/SL/Controller/Helper/GetModels/Paginated.pm
new file mode 100644 (file)
index 0000000..a40acae
--- /dev/null
@@ -0,0 +1,316 @@
+package SL::Controller::Helper::GetModels::Paginated;
+
+use strict;
+use parent 'SL::Controller::Helper::GetModels::Base';
+
+use List::Util qw(min);
+
+use Rose::Object::MakeMethods::Generic (
+  scalar => [ qw(disabled per_page) ],
+  'scalar --get_set_init' => [ qw(form_params paginate_args) ],
+);
+
+sub init {
+  my ($self, %specs)               = @_;
+
+  $self->set_get_models(delete $specs{get_models});
+  $self->SUPER::init(%specs);
+
+  $self->per_page($self->get_models->manager->default_objects_per_page) unless $self->per_page;
+
+  $self->get_models->register_handlers(
+    callback   => sub { shift; $self->_callback_handler_for_paginated(@_) },
+    get_models => sub { shift; $self->_get_models_handler_for_paginated(@_) },
+  );
+
+  # $::lxdebug->dump(0, "CONSPEC", \%specs);
+}
+
+sub get_current_paginate_params {
+  my ($self, %args)   = @_;
+  return () unless $self->is_enabled;
+
+  my %paginate_params = $self->final_params(%args);
+
+  # try to use Filtered if available and nothing else is configured, but don't
+  # blow up if the controller does not use Filtered
+  my %paginate_args     = ref($self->paginate_args) eq 'CODE'       ? %{ $self->paginate_args->($self) }
+                        :     $self->paginate_args  eq '__FILTER__'
+                           && $self->get_models->filtered ? %{ $self->get_models->filtered->get_current_filter_params }
+                        :     $self->paginate_args  ne '__FILTER__' ? do { my $sub = $self->paginate_args; %{ $self->get_models->controller->$sub() } }
+                        :                                               ();
+
+  %args = $self->merge_args(\%args, \%paginate_args);
+
+  my $calculated_params = $self->get_models->manager->paginate(%paginate_params, args => \%args);
+
+  # $::lxdebug->dump(0, "get_current_paginate_params: ", $calculated_params);
+
+  return %{ $calculated_params };
+}
+
+sub disable_pagination {
+  my ($self)               = @_;
+  $self->disabled(1);
+}
+
+sub final_params {
+  my ($self, %params)      = @_;
+
+  my $from_form = {
+    page            => $::form->{ $self->form_params->[0] } || 1,
+    per_page        => $::form->{ $self->form_params->[1] } * 1,
+  };
+
+#  my $priv              = _priv($self);
+  $params{page}         = $from_form->{page}     unless defined $params{page};
+  $params{per_page}     = $from_form->{per_page} unless defined $params{per_page};
+
+  $params{page}         = ($params{page} * 1) || 1;
+  $params{per_page}     = ($params{per_page} * 1) || $self->per_page;
+
+  %params;
+}
+
+#
+# private functions
+#
+
+sub init_form_params {
+  [ qw(page per_page) ]
+}
+
+sub init_paginate_args {
+  '__FILTER__'
+}
+
+sub _callback_handler_for_paginated {
+  my ($self, %params) = @_;
+  my %form_params = $self->final_params;
+#  my $priv            = _priv($self);
+
+  if ($self->is_enabled && $form_params{page}) {
+    $params{ $self->form_params->[0] } = $form_params{page};
+    $params{ $self->form_params->[1] } = $form_params{per_page} if $form_params{per_page};
+  }
+
+  # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
+
+  return %params;
+}
+
+sub _get_models_handler_for_paginated {
+  my ($self, %params)    = @_;
+
+  $self->get_models->manager->paginate($self->final_params, args => \%params) if $self->is_enabled;
+
+  # $::lxdebug->dump(0, "GM handler for paginated; params nach modif (is_enabled? " . _is_enabled($self) . ")", \%params);
+
+  return %params;
+}
+
+sub is_enabled {
+  my ($self) = @_;
+  return !$self->disabled;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Controller::Helper::Paginated - A helper for semi-automatic handling
+of paginating lists of database models in a controller
+
+=head1 SYNOPSIS
+
+In a controller:
+
+  use SL::Controller::Helper::GetModels;
+  use SL::Controller::Helper::Paginated;
+
+  __PACKAGE__->make_paginated(
+    MODEL       => 'BackgroundJobHistory',
+    ONLY        => [ qw(list) ],
+    FORM_PARAMS => [ qw(page per_page) ],
+  );
+
+  sub action_list {
+    my ($self) = @_;
+
+    my $paginated_models = $self->get_models;
+    $self->render('controller/list', ENTRIES => $paginated_models);
+  }
+
+In said template:
+
+  [% USE L %]
+
+  <table>
+   <thead>
+    <tr>
+     ...
+    </tr>
+   </thead>
+
+   <tbody>
+    [% FOREACH entry = ENTRIES %]
+     <tr>
+      ...
+     </tr>
+    [% END %]
+   </tbody>
+  </table>
+
+  [% L.paginate_controls %]
+
+=head1 OVERVIEW
+
+This specialized helper module enables controllers to display a
+paginatable list of database models with as few lines as possible. It
+can also be combined trivially with the L<SL::Controller::Sorted>
+helper for sortable lists.
+
+For this to work the controller has to provide the information which
+indexes are eligible for paginateing etc. by a call to
+L<make_paginated> at compile time.
+
+The underlying functionality that enables the use of more than just
+the paginate helper is provided by the controller helper
+C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
+more information on it.
+
+A template can use the method C<paginate_controls> from the layout
+helper module C<L> which renders the links for navigation between the
+pages.
+
+This module requires that the Rose model managers use their C<Paginated>
+helper.
+
+The C<Paginated> helper hooks into the controller call to the action via
+a C<run_before> hook. This is done so that it can remember the paginate
+parameters that were used in the current view.
+
+=head1 PACKAGE FUNCTIONS
+
+=over 4
+
+=item C<make_paginated %paginate_spec>
+
+This function must be called by a controller at compile time. It is
+uesd to set the various parameters required for this helper to do its
+magic.
+
+The hash C<%paginate_spec> can include the following parameters:
+
+=over 4
+
+=item * C<MODEL>
+
+Optional. A string: the name of the Rose database model that is used
+as a default in certain cases. If this parameter is missing then it is
+derived from the controller's package (e.g. for the controller
+C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
+C<BackgroundJobHistory>).
+
+=item * C<PAGINATE_ARGS>
+
+Optional. Either a code reference or the name of function to be called
+on the controller importing this helper.
+
+If this funciton is given then the paginate helper calls it whenever
+it has to count the total number of models for calculating the number
+of pages to display. The function must return a hash reference with
+elements suitable for passing to a Rose model manager's C<get_all>
+function.
+
+This can be used e.g. when filtering is used.
+
+=item * C<PER_PAGE>
+
+Optional. An integer: the number of models to return per page.
+
+Defaults to the underlying database model's default number of models
+per page.
+
+=item * C<FORM_PARAMS>
+
+Optional. An array reference with exactly two strings that name the
+indexes in C<$::form> in which the current page's number (the first
+element in the array) and the number of models per page (the second
+element in the array) are stored.
+
+Defaults to the values C<page> and C<per_page> if missing.
+
+=item * C<ONLY>
+
+Optional. An array reference containing a list of action names for
+which the paginate parameters should be saved. If missing or empty then
+all actions invoked on the controller are monitored.
+
+=back
+
+=back
+
+=head1 INSTANCE FUNCTIONS
+
+These functions are called on a controller instance.
+
+=over 4
+
+=item C<get_paginate_spec>
+
+Returns a hash containing the currently active paginate
+parameters. The following keys are returned:
+
+=over 4
+
+=item * C<page>
+
+The currently active page number (numbering starts at 1).
+
+=item * C<per_page>
+
+Number of models per page (at least 1).
+
+=item * C<num_pages>
+
+Number of pages to display (at least 1).
+
+=item * C<common_pages>
+
+An array reference with one hash reference for each possible
+page. Each hash ref contains the keys C<active> (C<1> if that page is
+the currently active page), C<page> (the page number this hash
+reference describes) and C<visible> (whether or not it should be
+displayed).
+
+=back
+
+=item C<get_current_paginate_params>
+
+Returns a hash reference to the paginate spec structure given in the call
+to L<make_paginated> after normalization (hash reference construction,
+applying default parameters etc).
+
+=item C<disable_pagination>
+
+Disable pagination for the duration of the current action. Can be used
+when using the attribute C<ONLY> to L<make_paginated> does not
+cover all cases.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
diff --git a/SL/Controller/Helper/GetModels/Sorted.pm b/SL/Controller/Helper/GetModels/Sorted.pm
new file mode 100644 (file)
index 0000000..9e133b8
--- /dev/null
@@ -0,0 +1,367 @@
+package SL::Controller::Helper::GetModels::Sorted;
+
+use strict;
+use parent 'SL::Controller::Helper::GetModels::Base';
+
+use Carp;
+use List::MoreUtils qw(uniq);
+
+use Rose::Object::MakeMethods::Generic (
+  scalar => [ qw(by dir specs) ],
+  'scalar --get_set_init' => [ qw(form_params) ],
+);
+
+sub init {
+  my ($self, %specs) = @_;
+
+  $self->set_get_models(delete $specs{get_models});
+  my %model_sort_spec   = $self->get_models->manager->_sort_spec;
+
+  if (my $default = delete $specs{_default}) {
+    $self->by ($default->{by});
+    $self->dir($default->{dir});
+  } else {
+    $self->by ($model_sort_spec{default}[0]);
+    $self->dir($model_sort_spec{default}[1]);
+  }
+
+  while (my ($column, $spec) = each %specs) {
+    next if $column =~ m/^[A-Z_]+$/;
+
+    $spec = $specs{$column} = { title => $spec } if (ref($spec) || '') ne 'HASH';
+
+    $spec->{model}        ||= $self->get_models->model;
+    $spec->{model_column} ||= $column;
+  }
+  $self->specs(\%specs);
+
+  $self->get_models->register_handlers(
+    callback   => sub { shift; $self->_callback_handler_for_sorted(@_) },
+    get_models => sub { shift; $self->_get_models_handler_for_sorted(@_) },
+  );
+
+#   $::lxdebug->dump(0, "CONSPEC", \%specs);
+}
+
+sub get_current_sort_params {
+  my ($self, %params) = @_;
+
+  my %sort_params;
+  my ($by, $dir) = @{ $self->form_params };
+
+  if ($::form->{ $by }) {
+    %sort_params = (
+      sort_by  => $::form->{$by},
+      sort_dir => defined($::form->{$dir}) ? $::form->{$dir} * 1 : undef,
+    );
+  } elsif (!$self->by) {
+    %sort_params = %params;
+  } else {
+    %sort_params = (
+      sort_by  => $self->by,
+      sort_dir => $self->dir,
+    );
+  }
+
+  return %sort_params;
+}
+
+sub set_report_generator_sort_options {
+  my ($self, %params) = @_;
+
+  $params{$_} or croak("Missing parameter '$_'") for qw(report sortable_columns);
+
+  my %current_sort_params = $self->get_current_sort_params;
+
+  foreach my $col (@{ $params{sortable_columns} }) {
+    $params{report}->{columns}->{$col}->{link} = $self->get_models->get_callback(
+      sort_by  => $col,
+      sort_dir => ($current_sort_params{sort_by} eq $col ? 1 - $current_sort_params{sort_dir} : $current_sort_params{sort_dir}),
+    );
+  }
+
+  $params{report}->set_sort_indicator($current_sort_params{sort_by}, 1 - $current_sort_params{sort_dir});
+
+  if ($params{report}->{export}) {
+    $params{report}->{export}->{variable_list} = [ uniq(
+      @{ $params{report}->{export}->{variable_list} },
+      @{ $self->form_params }
+    )];
+  }
+}
+
+#
+# private functions
+#
+
+sub _callback_handler_for_sorted {
+  my ($self, %params) = @_;
+  my %spec = $self->get_current_sort_params;
+
+  if ($spec{sort_by}) {
+    $params{ $self->form_params->[0] } = $spec{sort_by};
+    $params{ $self->form_params->[1] } = $spec{sort_dir};
+  }
+
+  # $::lxdebug->dump(0, "CB handler for sorted; params nach modif:", \%params);
+
+  return %params;
+}
+
+sub _get_models_handler_for_sorted {
+  my ($self, %params) = @_;
+
+  my %sort_params     = $self->get_current_sort_params;
+  my $sort_spec       = $self->specs->{ $sort_params{sort_by} };
+
+  $params{sort_by}    = "SL::DB::Manager::$sort_spec->{model}"->make_sort_string(sort_by => $sort_spec->{model_column}, sort_dir => $sort_params{sort_dir});
+
+  # $::lxdebug->dump(0, "GM handler for sorted; params nach modif:", \%params);
+
+  return %params;
+}
+
+
+sub init_form_params {
+  [ qw(sort_by sort_dir) ]
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Controller::Helper::Sorted - A helper for semi-automatic handling
+of sorting lists of database models in a controller
+
+=head1 SYNOPSIS
+
+In a controller:
+
+  use SL::Controller::Helper::GetModels;
+  use SL::Controller::Helper::Sorted;
+
+  __PACKAGE__->make_sorted(
+    DEFAULT_BY   => 'run_at',
+    DEFAULT_DIR  => 1,
+    MODEL        => 'BackgroundJobHistory',
+    ONLY         => [ qw(list) ],
+
+    error        => $::locale->text('Error'),
+    package_name => $::locale->text('Package name'),
+    run_at       => $::locale->text('Run at'),
+  );
+
+  sub action_list {
+    my ($self) = @_;
+
+    my $sorted_models = $self->get_models;
+    $self->render('controller/list', ENTRIES => $sorted_models);
+  }
+
+In said template:
+
+  [% USE L %]
+
+  <table>
+   <tr>
+    <th>[% L.sortable_table_header('package_name') %]</th>
+    <th>[% L.sortable_table_header('run_at') %]</th>
+    <th>[% L.sortable_table_header('error') %]</th>
+   </tr>
+
+   [% FOREACH entry = ENTRIES %]
+    <tr>
+     <td>[% HTML.escape(entry.package_name) %]</td>
+     <td>[% HTML.escape(entry.run_at) %]</td>
+     <td>[% HTML.escape(entry.error) %]</td>
+    </tr>
+   [% END %]
+  </table>
+
+=head1 OVERVIEW
+
+This specialized helper module enables controllers to display a
+sortable list of database models with as few lines as possible.
+
+For this to work the controller has to provide the information which
+indexes are eligible for sorting etc. by a call to L<make_sorted> at
+compile time.
+
+The underlying functionality that enables the use of more than just
+the sort helper is provided by the controller helper C<GetModels>. It
+provides mechanisms for helpers like this one to hook into certain
+calls made by the controller (C<get_callback> and C<get_models>) so
+that the specialized helpers can inject their parameters into the
+calls to e.g. C<SL::DB::Manager::SomeModel::get_all>.
+
+A template on the other hand can use the method
+C<sortable_table_header> from the layout helper module C<L>.
+
+This module requires that the Rose model managers use their C<Sorted>
+helper.
+
+The C<Sorted> helper hooks into the controller call to the action via
+a C<run_before> hook. This is done so that it can remember the sort
+parameters that were used in the current view.
+
+=head1 PACKAGE FUNCTIONS
+
+=over 4
+
+=item C<make_sorted %sort_spec>
+
+This function must be called by a controller at compile time. It is
+uesd to set the various parameters required for this helper to do its
+magic.
+
+There are two sorts of keys in the hash C<%sort_spec>. The first kind
+is written in all upper-case. Those parameters are control
+parameters. The second kind are all lower-case and represent indexes
+that can be used for sorting (similar to database column names). The
+second kind are also the indexes you use in a template when calling
+C<[% L.sorted_table_header(...) %]>.
+
+Control parameters include the following:
+
+=over 4
+
+=item * C<MODEL>
+
+Optional. A string: the name of the Rose database model that is used
+as a default in certain cases. If this parameter is missing then it is
+derived from the controller's package (e.g. for the controller
+C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
+C<BackgroundJobHistory>).
+
+=item * C<DEFAULT_BY>
+
+Optional. A string: the index to sort by if the user hasn't clicked on
+any column yet (meaning: if the C<$::form> parameters for sorting do
+not contain a valid index).
+
+Defaults to the underlying database model's default sort column name.
+
+=item * C<DEFAULT_DIR>
+
+Optional. Default sort direction (ascending for trueish values,
+descrending for falsish values).
+
+Defaults to the underlying database model's default sort direction.
+
+=item * C<FORM_PARAMS>
+
+Optional. An array reference with exactly two strings that name the
+indexes in C<$::form> in which the sort index (the first element in
+the array) and sort direction (the second element in the array) are
+stored.
+
+Defaults to the values C<sort_by> and C<sort_dir> if missing.
+
+=item * C<ONLY>
+
+Optional. An array reference containing a list of action names for
+which the sort parameters should be saved. If missing or empty then
+all actions invoked on the controller are monitored.
+
+=back
+
+All keys that are written in all lower-case name indexes that can be
+used for sorting. Each value to such a key can be either a string or a
+hash reference containing certain elements. If the value is only a
+string then such a hash reference is constructed, and the string is
+used as the value for the C<title> key.
+
+These possible elements are:
+
+=over 4
+
+=item * C<title>
+
+Required. A user-displayable title to be used by functions like the
+layout helper's C<sortable_table_header>. Does not have a default
+value.
+
+Note that this string must be the untranslated English version of the
+string. The titles will be translated whenever they're requested.
+
+=item * C<model>
+
+Optional. The name of a Rose database model this sort index refers
+to. If missing then the value of C<$sort_spec{MODEL}> is used.
+
+=item * C<model_column>
+
+Optional. The name of the Rose database model column this sort index
+refers to. It must be one of the columns named by the model's
+C<Sorted> helper (not to be confused with the controller's C<Sorted>
+helper!).
+
+If missing it defaults to the key in C<%sort_spec> for which this hash
+reference is the value.
+
+=back
+
+=back
+
+=head1 INSTANCE FUNCTIONS
+
+These functions are called on a controller instance.
+
+=over 4
+
+=item C<get_sort_spec>
+
+Returns a hash containing the currently active sort parameters.
+
+The key C<by> contains the active sort index referring to the
+C<%sort_spec> given to L<make_sorted>.
+
+The key C<dir> is either C<1> or C<0>.
+
+=item C<get_current_sort_params>
+
+Returns a hash reference to the sort spec structure given in the call
+to L<make_sorted> after normalization (hash reference construction,
+applying default parameters etc).
+
+=item C<set_report_generator_sort_options %params>
+
+This function does three things with an instance of
+L<SL::ReportGenerator>:
+
+=over 4
+
+=item 1. it sets the sort indicator,
+
+=item 2. it sets the the links for those column headers that are
+sortable and
+
+=item 3. it adds the C<FORM_PARAMS> fields to the list of variables in
+the report generator's export options.
+
+=back
+
+The report generator instance must be passed as the parameter
+C<report>. The parameter C<sortable_columns> must be an array
+reference of column names that are sortable.
+
+The report generator instance must already have its columns and export
+options set via calls to its L<SL::ReportGenerator::set_columns> and
+L<SL::ReportGenerator::set_export_options> functions.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
diff --git a/SL/Controller/Helper/Paginated.pm b/SL/Controller/Helper/Paginated.pm
deleted file mode 100644 (file)
index 0db285f..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-package SL::Controller::Helper::Paginated;
-
-use strict;
-
-use Exporter qw(import);
-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 disable_pagination);
-
-use constant PRIV => '__paginatedhelper_priv';
-
-use List::Util qw(min);
-
-my %controller_paginate_spec;
-
-sub make_paginated {
-  my ($class, %specs)               = @_;
-
-  $specs{MODEL}                   ||=  $class->controller_name;
-  $specs{MODEL}                     =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
-  $specs{PER_PAGE}                ||= "SL::DB::Manager::$specs{MODEL}"->default_objects_per_page;
-  $specs{FORM_PARAMS}             ||= [ qw(page per_page) ];
-  $specs{PAGINATE_ARGS}           ||= '__FILTER__';
-  $specs{ONLY}                    ||= [];
-  $specs{ONLY}                      = [ $specs{ONLY} ] if !ref $specs{ONLY};
-  $specs{ONLY_MAP}                  = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
-
-  $controller_paginate_spec{$class} = \%specs;
-
-  my %hook_params                   = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
-  $class->run_before('_save_current_paginate_params', %hook_params);
-
-  SL::Controller::Helper::GetModels::register_get_models_handlers(
-    $class,
-    callback   => '_callback_handler_for_paginated',
-    get_models => '_get_models_handler_for_paginated',
-    ONLY       => $specs{ONLY},
-  );
-
-  # $::lxdebug->dump(0, "CONSPEC", \%specs);
-}
-
-sub get_paginate_spec {
-  my ($class_or_self) = @_;
-
-  return $controller_paginate_spec{ref($class_or_self) || $class_or_self};
-}
-
-sub get_current_paginate_params {
-  my ($self, %params)   = @_;
-
-  my $spec              = $self->get_paginate_spec;
-
-  my $priv              = _priv($self);
-  $params{page}         = $priv->{page}     unless defined $params{page};
-  $params{per_page}     = $priv->{per_page} unless defined $params{per_page};
-
-  my %paginate_params   =  (
-    page                => ($params{page}     * 1) || 1,
-    per_page            => ($params{per_page} * 1) || $spec->{PER_PAGE},
-  );
-
-  # try to use Filtered if available and nothing else is configured, but don't
-  # blow up if the controller does not use Filtered
-  my %paginate_args     = ref($spec->{PAGINATE_ARGS}) eq 'CODE'       ? %{ $spec->{PAGINATE_ARGS}->($self) }
-                        :     $spec->{PAGINATE_ARGS}  eq '__FILTER__'
-                           && $self->can('get_current_filter_params') ? $self->get_current_filter_params
-                        :     $spec->{PAGINATE_ARGS}  ne '__FILTER__' ? do { my $sub = $spec->{PAGINATE_ARGS}; %{ $self->$sub() } }
-                        :                                               ();
-  my $calculated_params = "SL::DB::Manager::$spec->{MODEL}"->paginate(%paginate_params, args => \%paginate_args);
-
-  # $::lxdebug->dump(0, "get_current_paginate_params: ", $calculated_params);
-
-  return %{ $calculated_params };
-}
-
-sub disable_pagination {
-  my ($self)               = @_;
-  _priv($self)->{disabled} = 1;
-}
-
-#
-# private functions
-#
-
-sub _save_current_paginate_params {
-  my ($self)        = @_;
-
-  return if !_is_enabled($self);
-
-  my $paginate_spec = $self->get_paginate_spec;
-  $self->{PRIV()}   = {
-    page            => $::form->{ $paginate_spec->{FORM_PARAMS}->[0] } || 1,
-    per_page        => $::form->{ $paginate_spec->{FORM_PARAMS}->[1] } * 1,
-  };
-
-  # $::lxdebug->message(0, "saving current paginate params to " . $self->{PRIV()}->{page} . ' / ' . $self->{PRIV()}->{per_page});
-}
-
-sub _callback_handler_for_paginated {
-  my ($self, %params) = @_;
-  my $priv            = _priv($self);
-
-  if (_is_enabled($self) && $priv->{page}) {
-    my $paginate_spec                             = $self->get_paginate_spec;
-    $params{ $paginate_spec->{FORM_PARAMS}->[0] } = $priv->{page};
-    $params{ $paginate_spec->{FORM_PARAMS}->[1] } = $priv->{per_page} if $priv->{per_page};
-  }
-
-  # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
-
-  return %params;
-}
-
-sub _get_models_handler_for_paginated {
-  my ($self, %params)    = @_;
-  my $spec               = $self->get_paginate_spec;
-  $params{model}       ||= $spec->{MODEL};
-
-  "SL::DB::Manager::$params{model}"->paginate($self->get_current_paginate_params, args => \%params) if _is_enabled($self);
-
-  # $::lxdebug->dump(0, "GM handler for paginated; params nach modif (is_enabled? " . _is_enabled($self) . ")", \%params);
-
-  return %params;
-}
-
-sub _priv {
-  my ($self)        = @_;
-  $self->{PRIV()} ||= {};
-  return $self->{PRIV()};
-}
-
-sub _is_enabled {
-  my ($self) = @_;
-  return !_priv($self)->{disabled} && ($self->get_paginate_spec->{ONLY_MAP}->{$self->action_name} || $self->get_paginate_spec->{ONLY_MAP}->{'__ALL__'});
-}
-
-1;
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Controller::Helper::Paginated - A helper for semi-automatic handling
-of paginating lists of database models in a controller
-
-=head1 SYNOPSIS
-
-In a controller:
-
-  use SL::Controller::Helper::GetModels;
-  use SL::Controller::Helper::Paginated;
-
-  __PACKAGE__->make_paginated(
-    MODEL       => 'BackgroundJobHistory',
-    ONLY        => [ qw(list) ],
-    FORM_PARAMS => [ qw(page per_page) ],
-  );
-
-  sub action_list {
-    my ($self) = @_;
-
-    my $paginated_models = $self->get_models;
-    $self->render('controller/list', ENTRIES => $paginated_models);
-  }
-
-In said template:
-
-  [% USE L %]
-
-  <table>
-   <thead>
-    <tr>
-     ...
-    </tr>
-   </thead>
-
-   <tbody>
-    [% FOREACH entry = ENTRIES %]
-     <tr>
-      ...
-     </tr>
-    [% END %]
-   </tbody>
-  </table>
-
-  [% L.paginate_controls %]
-
-=head1 OVERVIEW
-
-This specialized helper module enables controllers to display a
-paginatable list of database models with as few lines as possible. It
-can also be combined trivially with the L<SL::Controller::Sorted>
-helper for sortable lists.
-
-For this to work the controller has to provide the information which
-indexes are eligible for paginateing etc. by a call to
-L<make_paginated> at compile time.
-
-The underlying functionality that enables the use of more than just
-the paginate helper is provided by the controller helper
-C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
-more information on it.
-
-A template can use the method C<paginate_controls> from the layout
-helper module C<L> which renders the links for navigation between the
-pages.
-
-This module requires that the Rose model managers use their C<Paginated>
-helper.
-
-The C<Paginated> helper hooks into the controller call to the action via
-a C<run_before> hook. This is done so that it can remember the paginate
-parameters that were used in the current view.
-
-=head1 PACKAGE FUNCTIONS
-
-=over 4
-
-=item C<make_paginated %paginate_spec>
-
-This function must be called by a controller at compile time. It is
-uesd to set the various parameters required for this helper to do its
-magic.
-
-The hash C<%paginate_spec> can include the following parameters:
-
-=over 4
-
-=item * C<MODEL>
-
-Optional. A string: the name of the Rose database model that is used
-as a default in certain cases. If this parameter is missing then it is
-derived from the controller's package (e.g. for the controller
-C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
-C<BackgroundJobHistory>).
-
-=item * C<PAGINATE_ARGS>
-
-Optional. Either a code reference or the name of function to be called
-on the controller importing this helper.
-
-If this funciton is given then the paginate helper calls it whenever
-it has to count the total number of models for calculating the number
-of pages to display. The function must return a hash reference with
-elements suitable for passing to a Rose model manager's C<get_all>
-function.
-
-This can be used e.g. when filtering is used.
-
-=item * C<PER_PAGE>
-
-Optional. An integer: the number of models to return per page.
-
-Defaults to the underlying database model's default number of models
-per page.
-
-=item * C<FORM_PARAMS>
-
-Optional. An array reference with exactly two strings that name the
-indexes in C<$::form> in which the current page's number (the first
-element in the array) and the number of models per page (the second
-element in the array) are stored.
-
-Defaults to the values C<page> and C<per_page> if missing.
-
-=item * C<ONLY>
-
-Optional. An array reference containing a list of action names for
-which the paginate parameters should be saved. If missing or empty then
-all actions invoked on the controller are monitored.
-
-=back
-
-=back
-
-=head1 INSTANCE FUNCTIONS
-
-These functions are called on a controller instance.
-
-=over 4
-
-=item C<get_paginate_spec>
-
-Returns a hash containing the currently active paginate
-parameters. The following keys are returned:
-
-=over 4
-
-=item * C<page>
-
-The currently active page number (numbering starts at 1).
-
-=item * C<per_page>
-
-Number of models per page (at least 1).
-
-=item * C<num_pages>
-
-Number of pages to display (at least 1).
-
-=item * C<common_pages>
-
-An array reference with one hash reference for each possible
-page. Each hash ref contains the keys C<active> (C<1> if that page is
-the currently active page), C<page> (the page number this hash
-reference describes) and C<visible> (whether or not it should be
-displayed).
-
-=back
-
-=item C<get_current_paginate_params>
-
-Returns a hash reference to the paginate spec structure given in the call
-to L<make_paginated> after normalization (hash reference construction,
-applying default parameters etc).
-
-=item C<disable_pagination>
-
-Disable pagination for the duration of the current action. Can be used
-when using the attribute C<ONLY> to L<make_paginated> does not
-cover all cases.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
-
-=cut
diff --git a/SL/Controller/Helper/Sorted.pm b/SL/Controller/Helper/Sorted.pm
deleted file mode 100644 (file)
index 2bdc51b..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-package SL::Controller::Helper::Sorted;
-
-use strict;
-
-use Carp;
-use List::MoreUtils qw(uniq);
-
-use Exporter qw(import);
-our @EXPORT = qw(make_sorted get_sort_spec get_current_sort_params set_report_generator_sort_options
-                 _save_current_sort_params _get_models_handler_for_sorted _callback_handler_for_sorted);
-
-use constant PRIV => '__sortedhelperpriv';
-
-my %controller_sort_spec;
-
-sub make_sorted {
-  my ($class, %specs) = @_;
-
-  $specs{MODEL} ||=  $class->controller_name;
-  $specs{MODEL}   =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
-
-  while (my ($column, $spec) = each %specs) {
-    next if $column =~ m/^[A-Z_]+$/;
-
-    $spec = $specs{$column} = { title => $spec } if (ref($spec) || '') ne 'HASH';
-
-    $spec->{model}        ||= $specs{MODEL};
-    $spec->{model_column} ||= $column;
-  }
-
-  my %model_sort_spec   = "SL::DB::Manager::$specs{MODEL}"->_sort_spec;
-  $specs{DEFAULT_DIR}   = $specs{DEFAULT_DIR} ? 1 : defined($specs{DEFAULT_DIR}) ? $specs{DEFAULT_DIR} * 1 : $model_sort_spec{default}->[1];
-  $specs{DEFAULT_BY}  ||= $model_sort_spec{default}->[0];
-  $specs{FORM_PARAMS} ||= [ qw(sort_by sort_dir) ];
-  $specs{ONLY}        ||= [];
-  $specs{ONLY}          = [ $specs{ONLY} ] if !ref $specs{ONLY};
-
-  $controller_sort_spec{$class} = \%specs;
-
-  my %hook_params = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
-  $class->run_before('_save_current_sort_params', %hook_params);
-
-  SL::Controller::Helper::GetModels::register_get_models_handlers(
-    $class,
-    callback   => '_callback_handler_for_sorted',
-    get_models => '_get_models_handler_for_sorted',
-    ONLY       => $specs{ONLY},
-  );
-
-  # $::lxdebug->dump(0, "CONSPEC", \%specs);
-}
-
-sub get_sort_spec {
-  my ($class_or_self) = @_;
-
-  return $controller_sort_spec{ref($class_or_self) || $class_or_self};
-}
-
-sub get_current_sort_params {
-  my ($self, %params) = @_;
-
-  my $sort_spec = $self->get_sort_spec;
-
-  if (!$params{sort_by}) {
-    my $priv          = $self->{PRIV()} || {};
-    $params{sort_by}  = $priv->{by};
-    $params{sort_dir} = $priv->{dir};
-  }
-
-  my $by          = $params{sort_by} || $sort_spec->{DEFAULT_BY};
-  my %sort_params = (
-    dir => defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec->{DEFAULT_DIR},
-    by  => $sort_spec->{$by} ? $by : $sort_spec->{DEFAULT_BY},
-  );
-
-  return %sort_params;
-}
-
-sub set_report_generator_sort_options {
-  my ($self, %params) = @_;
-
-  $params{$_} or croak("Missing parameter '$_'") for qw(report sortable_columns);
-
-  my %current_sort_params = $self->get_current_sort_params;
-
-  foreach my $col (@{ $params{sortable_columns} }) {
-    $params{report}->{columns}->{$col}->{link} = $self->get_callback(
-      sort_by  => $col,
-      sort_dir => ($current_sort_params{by} eq $col ? 1 - $current_sort_params{dir} : $current_sort_params{dir}),
-    );
-  }
-
-  $params{report}->set_sort_indicator($current_sort_params{by}, 1 - $current_sort_params{dir});
-
-  if ($params{report}->{export}) {
-    $params{report}->{export}->{variable_list} = [ uniq(
-      @{ $params{report}->{export}->{variable_list} },
-      @{ $self->get_sort_spec->{FORM_PARAMS} }
-    )];
-  }
-}
-
-#
-# private functions
-#
-
-sub _save_current_sort_params {
-  my ($self)      = @_;
-
-  my $sort_spec   = $self->get_sort_spec;
-  my $dir_idx     = $sort_spec->{FORM_PARAMS}->[1];
-  $self->{PRIV()} = {
-    by            =>   $::form->{ $sort_spec->{FORM_PARAMS}->[0] },
-    dir           => defined($::form->{$dir_idx}) ? $::form->{$dir_idx} * 1 : undef,
-  };
-
-  # $::lxdebug->message(0, "saving current sort params to " . $self->{PRIV()}->{by} . ' / ' . $self->{PRIV()}->{dir});
-}
-
-sub _callback_handler_for_sorted {
-  my ($self, %params) = @_;
-
-  my $priv = $self->{PRIV()} || {};
-  if ($priv->{by}) {
-    my $sort_spec                             = $self->get_sort_spec;
-    $params{ $sort_spec->{FORM_PARAMS}->[0] } = $priv->{by};
-    $params{ $sort_spec->{FORM_PARAMS}->[1] } = $priv->{dir};
-  }
-
-  # $::lxdebug->dump(0, "CB handler for sorted; params nach modif:", \%params);
-
-  return %params;
-}
-
-sub _get_models_handler_for_sorted {
-  my ($self, %params) = @_;
-
-  my %sort_params     = $self->get_current_sort_params;
-  my $sort_spec       = $self->get_sort_spec->{ $sort_params{by} };
-
-  $params{model}      = $sort_spec->{model};
-  $params{sort_by}    = "SL::DB::Manager::$params{model}"->make_sort_string(sort_by => $sort_spec->{model_column}, sort_dir => $sort_params{dir});
-
-  # $::lxdebug->dump(0, "GM handler for sorted; params nach modif:", \%params);
-
-  return %params;
-}
-
-1;
-__END__
-
-=pod
-
-=encoding utf8
-
-=head1 NAME
-
-SL::Controller::Helper::Sorted - A helper for semi-automatic handling
-of sorting lists of database models in a controller
-
-=head1 SYNOPSIS
-
-In a controller:
-
-  use SL::Controller::Helper::GetModels;
-  use SL::Controller::Helper::Sorted;
-
-  __PACKAGE__->make_sorted(
-    DEFAULT_BY   => 'run_at',
-    DEFAULT_DIR  => 1,
-    MODEL        => 'BackgroundJobHistory',
-    ONLY         => [ qw(list) ],
-
-    error        => $::locale->text('Error'),
-    package_name => $::locale->text('Package name'),
-    run_at       => $::locale->text('Run at'),
-  );
-
-  sub action_list {
-    my ($self) = @_;
-
-    my $sorted_models = $self->get_models;
-    $self->render('controller/list', ENTRIES => $sorted_models);
-  }
-
-In said template:
-
-  [% USE L %]
-
-  <table>
-   <tr>
-    <th>[% L.sortable_table_header('package_name') %]</th>
-    <th>[% L.sortable_table_header('run_at') %]</th>
-    <th>[% L.sortable_table_header('error') %]</th>
-   </tr>
-
-   [% FOREACH entry = ENTRIES %]
-    <tr>
-     <td>[% HTML.escape(entry.package_name) %]</td>
-     <td>[% HTML.escape(entry.run_at) %]</td>
-     <td>[% HTML.escape(entry.error) %]</td>
-    </tr>
-   [% END %]
-  </table>
-
-=head1 OVERVIEW
-
-This specialized helper module enables controllers to display a
-sortable list of database models with as few lines as possible.
-
-For this to work the controller has to provide the information which
-indexes are eligible for sorting etc. by a call to L<make_sorted> at
-compile time.
-
-The underlying functionality that enables the use of more than just
-the sort helper is provided by the controller helper C<GetModels>. It
-provides mechanisms for helpers like this one to hook into certain
-calls made by the controller (C<get_callback> and C<get_models>) so
-that the specialized helpers can inject their parameters into the
-calls to e.g. C<SL::DB::Manager::SomeModel::get_all>.
-
-A template on the other hand can use the method
-C<sortable_table_header> from the layout helper module C<L>.
-
-This module requires that the Rose model managers use their C<Sorted>
-helper.
-
-The C<Sorted> helper hooks into the controller call to the action via
-a C<run_before> hook. This is done so that it can remember the sort
-parameters that were used in the current view.
-
-=head1 PACKAGE FUNCTIONS
-
-=over 4
-
-=item C<make_sorted %sort_spec>
-
-This function must be called by a controller at compile time. It is
-uesd to set the various parameters required for this helper to do its
-magic.
-
-There are two sorts of keys in the hash C<%sort_spec>. The first kind
-is written in all upper-case. Those parameters are control
-parameters. The second kind are all lower-case and represent indexes
-that can be used for sorting (similar to database column names). The
-second kind are also the indexes you use in a template when calling
-C<[% L.sorted_table_header(...) %]>.
-
-Control parameters include the following:
-
-=over 4
-
-=item * C<MODEL>
-
-Optional. A string: the name of the Rose database model that is used
-as a default in certain cases. If this parameter is missing then it is
-derived from the controller's package (e.g. for the controller
-C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
-C<BackgroundJobHistory>).
-
-=item * C<DEFAULT_BY>
-
-Optional. A string: the index to sort by if the user hasn't clicked on
-any column yet (meaning: if the C<$::form> parameters for sorting do
-not contain a valid index).
-
-Defaults to the underlying database model's default sort column name.
-
-=item * C<DEFAULT_DIR>
-
-Optional. Default sort direction (ascending for trueish values,
-descrending for falsish values).
-
-Defaults to the underlying database model's default sort direction.
-
-=item * C<FORM_PARAMS>
-
-Optional. An array reference with exactly two strings that name the
-indexes in C<$::form> in which the sort index (the first element in
-the array) and sort direction (the second element in the array) are
-stored.
-
-Defaults to the values C<sort_by> and C<sort_dir> if missing.
-
-=item * C<ONLY>
-
-Optional. An array reference containing a list of action names for
-which the sort parameters should be saved. If missing or empty then
-all actions invoked on the controller are monitored.
-
-=back
-
-All keys that are written in all lower-case name indexes that can be
-used for sorting. Each value to such a key can be either a string or a
-hash reference containing certain elements. If the value is only a
-string then such a hash reference is constructed, and the string is
-used as the value for the C<title> key.
-
-These possible elements are:
-
-=over 4
-
-=item * C<title>
-
-Required. A user-displayable title to be used by functions like the
-layout helper's C<sortable_table_header>. Does not have a default
-value.
-
-Note that this string must be the untranslated English version of the
-string. The titles will be translated whenever they're requested.
-
-=item * C<model>
-
-Optional. The name of a Rose database model this sort index refers
-to. If missing then the value of C<$sort_spec{MODEL}> is used.
-
-=item * C<model_column>
-
-Optional. The name of the Rose database model column this sort index
-refers to. It must be one of the columns named by the model's
-C<Sorted> helper (not to be confused with the controller's C<Sorted>
-helper!).
-
-If missing it defaults to the key in C<%sort_spec> for which this hash
-reference is the value.
-
-=back
-
-=back
-
-=head1 INSTANCE FUNCTIONS
-
-These functions are called on a controller instance.
-
-=over 4
-
-=item C<get_sort_spec>
-
-Returns a hash containing the currently active sort parameters.
-
-The key C<by> contains the active sort index referring to the
-C<%sort_spec> given to L<make_sorted>.
-
-The key C<dir> is either C<1> or C<0>.
-
-=item C<get_current_sort_params>
-
-Returns a hash reference to the sort spec structure given in the call
-to L<make_sorted> after normalization (hash reference construction,
-applying default parameters etc).
-
-=item C<set_report_generator_sort_options %params>
-
-This function does three things with an instance of
-L<SL::ReportGenerator>:
-
-=over 4
-
-=item 1. it sets the sort indicator,
-
-=item 2. it sets the the links for those column headers that are
-sortable and
-
-=item 3. it adds the C<FORM_PARAMS> fields to the list of variables in
-the report generator's export options.
-
-=back
-
-The report generator instance must be passed as the parameter
-C<report>. The parameter C<sortable_columns> must be an array
-reference of column names that are sortable.
-
-The report generator instance must already have its columns and export
-options set via calls to its L<SL::ReportGenerator::set_columns> and
-L<SL::ReportGenerator::set_export_options> functions.
-
-=back
-
-=head1 BUGS
-
-Nothing here yet.
-
-=head1 AUTHOR
-
-Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
-
-=cut
index ef534ce..7c53573 100644 (file)
@@ -465,17 +465,19 @@ sub paginate_controls {
   my ($self, %params) = _hashify(1, @_);
 
   my $controller      = $self->{CONTEXT}->stash->get('SELF');
-  my $paginate_spec   = $controller->get_paginate_spec;
-  my %paginate_params = $controller->get_current_paginate_params;
+  my $pager           = $params{models}->paginated;
+#  my $paginate_spec   = $controller->get_paginate_spec;
+
+  my %paginate_params = $params{models}->get_paginate_args;
 
   my %template_params = (
     pages             => \%paginate_params,
     url_maker         => sub {
       my %url_params                                    = _hashify(0, @_);
-      $url_params{ $paginate_spec->{FORM_PARAMS}->[0] } = delete $url_params{page};
-      $url_params{ $paginate_spec->{FORM_PARAMS}->[1] } = delete $url_params{per_page} if exists $url_params{per_page};
+      $url_params{ $pager->form_params->[0] } = delete $url_params{page};
+      $url_params{ $pager->form_params->[1] } = delete $url_params{per_page} if exists $url_params{per_page};
 
-      return $controller->get_callback(%url_params);
+      return $params{models}->get_callback(%url_params);
     },
     %params,
   );