nicht hochgeladene Datei abfangen
[kivitendo-erp.git] / SL / Controller / Helper / Sorted.pm
index 817f803..98c0a7c 100644 (file)
@@ -2,33 +2,40 @@ 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 _save_current_sort_params _get_models_handler_for_sorted _callback_handler_for_sorted);
+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, $current_sort_by, $current_sort_dir);
+my %controller_sort_spec;
 
 sub make_sorted {
   my ($class, %specs) = @_;
 
-  $specs{MODEL} ||=  $class->_controller_name;
+  $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;
+    $spec = $specs{$column} = { title => $spec } if (ref($spec) || '') ne 'HASH';
 
     $spec->{model}        ||= $specs{MODEL};
     $spec->{model_column} ||= $column;
   }
 
-  $specs{DEFAULT_DIR}   = $specs{DEFAULT_DIR} || !defined($specs{DEFAULT_DIR}) ? 1 : 0;
-  $specs{DEFAULT_BY}  ||= { "SL::DB::Manager::$specs{MODEL}"->_sort_spec }->{default}->[0];
+  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 = \%specs;
+  $controller_sort_spec{$class} = \%specs;
 
   my %hook_params = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
   $class->run_before('_save_current_sort_params', %hook_params);
@@ -46,7 +53,7 @@ sub make_sorted {
 sub get_sort_spec {
   my ($class_or_self) = @_;
 
-  return $controller_sort_spec;
+  return $controller_sort_spec{ref($class_or_self) || $class_or_self};
 }
 
 sub get_current_sort_params {
@@ -55,8 +62,9 @@ sub get_current_sort_params {
   my $sort_spec = $self->get_sort_spec;
 
   if (!$params{sort_by}) {
-    $params{sort_by}  = $current_sort_by;
-    $params{sort_dir} = $current_sort_dir;
+    my $priv          = $self->{PRIV()} || {};
+    $params{sort_by}  = $priv->{by};
+    $params{sort_dir} = $priv->{dir};
   }
 
   my $by          = $params{sort_by} || $sort_spec->{DEFAULT_BY};
@@ -68,27 +76,54 @@ sub get_current_sort_params {
   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 ($self)      = @_;
 
-  my $sort_spec     = $self->get_sort_spec;
-  $current_sort_by  =   $::form->{ $sort_spec->{FORM_PARAMS}->[0] };
-  $current_sort_dir = !!$::form->{ $sort_spec->{FORM_PARAMS}->[1] } * 1;
+  my $sort_spec   = $self->get_sort_spec;
+  $self->{PRIV()} = {
+    by            =>   $::form->{ $sort_spec->{FORM_PARAMS}->[0] },
+    dir           => !!$::form->{ $sort_spec->{FORM_PARAMS}->[1] } * 1,
+  };
 
-  # $::lxdebug->message(0, "saving current sort params to $current_sort_by / $current_sort_dir");
+  # $::lxdebug->message(0, "saving current sort params to " . $self->{PRIV()}->{by} . ' / ' . $self->{PRIV()}->{dir});
 }
 
 sub _callback_handler_for_sorted {
   my ($self, %params) = @_;
 
-  if ($current_sort_by) {
+  my $priv = $self->{PRIV()} || {};
+  if ($priv->{by}) {
     my $sort_spec                             = $self->get_sort_spec;
-    $params{ $sort_spec->{FORM_PARAMS}->[0] } = $current_sort_by;
-    $params{ $sort_spec->{FORM_PARAMS}->[1] } = $current_sort_dir;
+    $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);
@@ -143,7 +178,7 @@ In a controller:
   sub action_list {
     my ($self) = @_;
 
-    my $sorted_models = $self->get_sorted;
+    my $sorted_models = $self->get_models;
     $self->render('controller/list', ENTRIES => $sorted_models);
   }
 
@@ -186,6 +221,9 @@ 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.
@@ -207,31 +245,32 @@ 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 (all required parameters
-occur first):
+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>
 
-Required. A string: the index to sort by if the user hasn't clicked on
+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 C<1> if missing.
-
-=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>).
+Defaults to the underlying database model's default sort direction.
 
 =item * C<FORM_PARAMS>
 
@@ -266,6 +305,9 @@ 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
@@ -306,6 +348,31 @@ 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