Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision ec3a4636

Von Sven Schöling vor etwa 11 Jahren hinzugefügt

  • ID ec3a4636c1d58339915614120cd82759150d7641
  • Vorgänger cf826cc8
  • Nachfolger 0f491583

Erste Version GetModels rewrite

known bugs:
disable pagination funktioniert nicht
compiletime optimizations werden noch nicht benutzt
doku fehlt

Unterschiede anzeigen:

SL/Controller/DeliveryPlan.pm
6 6
use Clone qw(clone);
7 7
use SL::DB::OrderItem;
8 8
use SL::Controller::Helper::GetModels;
9
use SL::Controller::Helper::Paginated;
10
use SL::Controller::Helper::Sorted;
11
use SL::Controller::Helper::Filtered;
12 9
use SL::Controller::Helper::ReportGenerator;
13 10
use SL::Locale::String;
14 11

  
15 12
use Rose::Object::MakeMethods::Generic (
16 13
  scalar => [ qw(db_args flat_filter) ],
14
  'scalar --get_set_init' => [ qw(models) ],
17 15
);
18 16

  
19 17
__PACKAGE__->run_before(sub { $::auth->assert('sales_order_edit'); });
20 18

  
21
__PACKAGE__->make_filtered(
22
  MODEL             => 'OrderItem',
23
  LAUNDER_TO        => 'filter'
24
);
25
__PACKAGE__->make_paginated(
26
  MODEL         => 'OrderItem',
27
  ONLY          => [ qw(list) ],
28
);
29

  
30
__PACKAGE__->make_sorted(
31
  MODEL             => 'OrderItem',
32
  ONLY              => [ qw(list) ],
33

  
34
  DEFAULT_BY        => 'reqdate',
35
  DEFAULT_DIR       => 1,
36

  
19
#__PACKAGE__->make_filtered(
20
#  MODEL             => 'OrderItem',
21
#  LAUNDER_TO        => 'filter'
22
#);
23
#__PACKAGE__->make_paginated(
24
#  MODEL         => 'OrderItem',
25
#  ONLY          => [ qw(list) ],
26
#);
27
#
28
#__PACKAGE__->make_sorted(
29
#  MODEL             => 'OrderItem',
30
#  ONLY              => [ qw(list) ],
31
#
32
#  DEFAULT_BY        => 'reqdate',
33
#  DEFAULT_DIR       => 1,
34
#
35
#  reqdate           => t8('Reqdate'),
36
#  description       => t8('Description'),
37
#  partnumber        => t8('Part Number'),
38
#  qty               => t8('Qty'),
39
#  shipped_qty       => t8('shipped'),
40
#  not_shipped_qty   => t8('not shipped'),
41
#  ordnumber         => t8('Order'),
42
#  customer          => t8('Customer'),
43
#);
44

  
45
my %sort_columns = (
37 46
  reqdate           => t8('Reqdate'),
38 47
  description       => t8('Description'),
39 48
  partnumber        => t8('Part Number'),
......
121 130

  
122 131
  $self->make_filter_summary;
123 132

  
124
  my $orderitems = $self->get_models(query => $delivery_plan_query, with_objects => [ 'order', 'order.customer', 'part' ]);
133
  my $orderitems = $self->models->get;
125 134

  
126 135
  $self->prepare_report;
127 136
  $self->report_generator_list_objects(report => $self->{report}, objects => $orderitems);
......
149 158
    not_shipped_qty   => {      sub => sub { $::form->format_amount(\%::myconfig, $_[0]->qty - $_[0]->shipped_qty, 2) . ' ' . $_[0]->unit } },
150 159
    ordnumber         => {      sub => sub { $_[0]->order->ordnumber                                                         },
151 160
                           obj_link => sub { $self->link_to($_[0]->order)                                                    } },
152
    customer          => {      sub => sub { $_[0]->order->customer->name                                                    },
161
    customer          => {      sub => sub { return ''; $_[0]->order->customer->name                                                    },
153 162
                           obj_link => sub { $self->link_to($_[0]->order->customer)                                          } },
154 163
  );
155 164

  
156
  map { $column_defs{$_}->{text} = $::locale->text( $self->get_sort_spec->{$_}->{title} ) } keys %column_defs;
165
  $column_defs{$_}->{text} = $sort_columns{$_} for keys %column_defs;
157 166

  
158 167
  $report->set_options(
159 168
    std_column_visibility => 1,
......
161 170
    output_format         => 'HTML',
162 171
    top_info_text         => $::locale->text('Delivery Plan for currently outstanding sales orders'),
163 172
    raw_top_info_text     => $self->render('delivery_plan/report_top',    { output => 0 }),
164
    raw_bottom_info_text  => $self->render('delivery_plan/report_bottom', { output => 0 }),
173
    raw_bottom_info_text  => $self->render('delivery_plan/report_bottom', { output => 0 }, models => $self->models),
165 174
    title                 => $::locale->text('Delivery Plan'),
166 175
    allow_pdf_export      => 1,
167 176
    allow_csv_export      => 1,
......
170 179
  $report->set_column_order(@columns);
171 180
  $report->set_export_options(qw(list filter));
172 181
  $report->set_options_from_form;
173
  $self->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
182
  $self->models->sorted->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
174 183

  
175
  $self->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
184
  $self->models->paginated->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
176 185
}
177 186

  
178 187
sub make_filter_summary {
......
209 218
  $self->{filter_summary} = join ', ', @filter_strings;
210 219
}
211 220

  
221
sub init_models {
222
  my ($self) = @_;
223

  
224
  SL::Controller::Helper::GetModels->new(
225
    controller => $self,
226
    model  => 'OrderItem', # defaults to controller
227
    filtered => {
228
      launder_to => 'filter',
229
    },
230
    sorted => {
231
      _default => {
232
        by        => 'reqdate',
233
        dir       => 1,
234
      },
235
      %sort_columns,
236
    },
237
    query => $delivery_plan_query,
238
    with_objects => [ 'order', 'order.customer', 'part' ],
239
  );
240
}
241

  
212 242
sub link_to {
213 243
  my ($self, $object, %params) = @_;
214 244

  
SL/Controller/Helper/Filtered.pm
1
package SL::Controller::Helper::Filtered;
2

  
3
use strict;
4

  
5
use Exporter qw(import);
6
use SL::Controller::Helper::ParseFilter ();
7
use List::MoreUtils qw(uniq);
8
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);
9

  
10
use constant PRIV => '__filteredhelper_priv';
11

  
12
my %controller_filter_spec;
13

  
14
sub make_filtered {
15
  my ($class, %specs)             = @_;
16

  
17
  $specs{MODEL}                 //=  $class->controller_name;
18
  $specs{MODEL}                   =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
19
  $specs{FORM_PARAMS}           //= 'filter';
20
  $specs{LAUNDER_TO}              = '__INPLACE__' unless exists $specs{LAUNDER_TO};
21
  $specs{ONLY}                  //= [];
22
  $specs{ONLY}                    = [ $specs{ONLY} ] if !ref $specs{ONLY};
23
  $specs{ONLY_MAP}                = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
24

  
25
  $controller_filter_spec{$class} = \%specs;
26

  
27
  my %hook_params                 = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
28
  $class->run_before('_save_current_filter_params', %hook_params);
29

  
30
  SL::Controller::Helper::GetModels::register_get_models_handlers(
31
    $class,
32
    callback   => '_callback_handler_for_filtered',
33
    get_models => '_get_models_handler_for_filtered',
34
    ONLY       => $specs{ONLY},
35
  );
36

  
37
  # $::lxdebug->dump(0, "CONSPEC", \%specs);
38
}
39

  
40
sub get_filter_spec {
41
  my ($class_or_self) = @_;
42

  
43
  return $controller_filter_spec{ref($class_or_self) || $class_or_self};
44
}
45

  
46
sub get_current_filter_params {
47
  my ($self)   = @_;
48

  
49
  return %{ _priv($self)->{filter_params} } if _priv($self)->{filter_params};
50

  
51
  require Carp;
52
  Carp::confess('It seems a GetModels plugin tries to access filter params before they got calculated. Make sure your make_filtered call comes first.');
53
}
54

  
55
sub _make_current_filter_params {
56
  my ($self, %params)   = @_;
57

  
58
  my $spec              = $self->get_filter_spec;
59
  my $filter            = $params{filter} // _priv($self)->{filter} // {},
60
  my %filter_args       = _get_filter_args($self, $spec);
61
  my %parse_filter_args = (
62
    class        => "SL::DB::Manager::$spec->{MODEL}",
63
    with_objects => $params{with_objects},
64
  );
65
  my $laundered;
66
  if ($spec->{LAUNDER_TO} eq '__INPLACE__') {
67

  
68
  } elsif ($spec->{LAUNDER_TO}) {
69
    $laundered = {};
70
    $parse_filter_args{launder_to} = $laundered;
71
  } else {
72
    $parse_filter_args{no_launder} = 1;
73
  }
74

  
75
  my %calculated_params = SL::Controller::Helper::ParseFilter::parse_filter($filter, %parse_filter_args);
76

  
77
  $calculated_params{query} = [
78
    @{ $calculated_params{query} || [] },
79
    @{ $filter_args{      query} || [] },
80
    @{ $params{           query} || [] },
81
  ];
82

  
83
  $calculated_params{with_objects} = [
84
    uniq
85
    @{ $calculated_params{with_objects} || [] },
86
    @{ $filter_args{      with_objects} || [] },
87
    @{ $params{           with_objects} || [] },
88
  ];
89

  
90
  if ($laundered) {
91
    if ($self->can($spec->{LAUNDER_TO})) {
92
      $self->${\ $spec->{LAUNDER_TO} }($laundered);
93
    } else {
94
      $self->{$spec->{LAUNDER_TO}} = $laundered;
95
    }
96
  }
97

  
98
  # $::lxdebug->dump(0, "get_current_filter_params: ", \%calculated_params);
99

  
100
  _priv($self)->{filter_params} = \%calculated_params;
101

  
102
  return %calculated_params;
103
}
104

  
105
sub disable_filtering {
106
  my ($self)               = @_;
107
  _priv($self)->{disabled} = 1;
108
}
109

  
110
#
111
# private functions
112
#
113

  
114
sub _get_filter_args {
115
  my ($self, $spec) = @_;
116

  
117
  $spec           ||= $self->get_filter_spec;
118

  
119
  my %filter_args   = ref($spec->{FILTER_ARGS}) eq 'CODE' ? %{ $spec->{FILTER_ARGS}->($self) }
120
                    :     $spec->{FILTER_ARGS}            ? do { my $sub = $spec->{FILTER_ARGS}; %{ $self->$sub() } }
121
                    :                                       ();
122
}
123

  
124
sub _save_current_filter_params {
125
  my ($self)        = @_;
126

  
127
  return if !_is_enabled($self);
128

  
129
  my $filter_spec = $self->get_filter_spec;
130
  $self->{PRIV()}{filter} = $::form->{ $filter_spec->{FORM_PARAMS} };
131

  
132
  # $::lxdebug->message(0, "saving current filter params to " . $self->{PRIV()}->{page} . ' / ' . $self->{PRIV()}->{per_page});
133
}
134

  
135
sub _callback_handler_for_filtered {
136
  my ($self, %params) = @_;
137
  my $priv            = _priv($self);
138

  
139
  if (_is_enabled($self) && $priv->{filter}) {
140
    my $filter_spec = $self->get_filter_spec;
141
    my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($priv->{filter}, $filter_spec->{FORM_PARAMS});
142
    %params         = (%params, @$flattened);
143
  }
144

  
145
  # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
146

  
147
  return %params;
148
}
149

  
150
sub _get_models_handler_for_filtered {
151
  my ($self, %params)    = @_;
152
  my $spec               = $self->get_filter_spec;
153

  
154
  # $::lxdebug->dump(0,  "params in get_models_for_filtered", \%params);
155

  
156
  my %filter_params;
157
  %filter_params = _make_current_filter_params($self, %params)  if _is_enabled($self);
158

  
159
  # $::lxdebug->dump(0, "GM handler for filtered; params nach modif (is_enabled? " . _is_enabled($self) . ")", \%params);
160

  
161
  return (%params, %filter_params);
162
}
163

  
164
sub _priv {
165
  my ($self)        = @_;
166
  $self->{PRIV()} ||= {};
167
  return $self->{PRIV()};
168
}
169

  
170
sub _is_enabled {
171
  my ($self) = @_;
172
  return !_priv($self)->{disabled} && ($self->get_filter_spec->{ONLY_MAP}->{$self->action_name} || $self->get_filter_spec->{ONLY_MAP}->{'__ALL__'});
173
}
174

  
175
1;
176

  
177
__END__
178

  
179
=pod
180

  
181
=encoding utf8
182

  
183
=head1 NAME
184

  
185
SL::Controller::Helper::Filtered - A helper for semi-automatic handling
186
of filtered lists of database models in a controller
187

  
188
=head1 SYNOPSIS
189

  
190
In a controller:
191

  
192
  use SL::Controller::Helper::GetModels;
193
  use SL::Controller::Helper::Filtered;
194

  
195
  __PACKAGE__->make_filter(
196
    MODEL       => 'Part',
197
    ONLY        => [ qw(list) ],
198
    FORM_PARAMS => [ qw(filter) ],
199
  );
200

  
201
  sub action_list {
202
    my ($self) = @_;
203

  
204
    my $filtered_models = $self->get_models(%addition_filters);
205
    $self->render('controller/list', ENTRIES => $filtered_models);
206
  }
207

  
208

  
209
=head1 OVERVIEW
210

  
211
This helper module enables use of the L<SL::Controller::Helper::ParseFilter>
212
methods in conjunction with the L<SL::Controller::Helper::GetModels> style of
213
plugins. Additional filters can be defined in the database models and filtering
214
can be reduced to a minimum of work.
215

  
216
This plugin can be combined with L<SL::Controller::Sorted> and
217
L<SL::Controller::Paginated> for filtered, sorted and paginated lists.
218

  
219
The controller has to provive information where to look for filter information
220
at compile time. This call is L<make_filtered>.
221

  
222
The underlying functionality that enables the use of more than just
223
the paginate helper is provided by the controller helper
224
C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
225
more information on it.
226

  
227
=head1 PACKAGE FUNCTIONS
228

  
229
=over 4
230

  
231
=item C<make_filtered %filter_spec>
232

  
233
This function must be called by a controller at compile time. It is
234
uesd to set the various parameters required for this helper to do its
235
magic.
236

  
237
Careful: If you want to use this in conjunction with
238
L<SL:Controller::Helper::Paginated>, you need to call C<make_filtered> first,
239
or the paginating will not get all the relevant information to estimate the
240
number of pages correctly. To ensure this does not happen, this module will
241
croak when it detects such a scenario.
242

  
243
The hash C<%filter_spec> can include the following parameters:
244

  
245
=over 4
246

  
247
=item * C<MODEL>
248

  
249
Optional. A string: the name of the Rose database model that is used
250
as a default in certain cases. If this parameter is missing then it is
251
derived from the controller's package (e.g. for the controller
252
C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
253
C<BackgroundJobHistory>).
254

  
255
=item * C<FORM_PARAMS>
256

  
257
Optional. Indicates a key in C<$::form> to be used as filter.
258

  
259
Defaults to the values C<filter> if missing.
260

  
261
=item * C<LAUNDER_TO>
262

  
263
Option. Indicates a target for laundered filter arguments in the controller.
264
Can be set to C<undef> to disable laundering, and can be set to method named or
265
hash keys of the controller. In the latter case the laundered structure will be
266
put there.
267

  
268
Defaults to inplace laundering which is not normally settable.
269

  
270
=item * C<ONLY>
271

  
272
Optional. An array reference containing a list of action names for
273
which the paginate parameters should be saved. If missing or empty then
274
all actions invoked on the controller are monitored.
275

  
276
=back
277

  
278
=back
279

  
280
=head1 INSTANCE FUNCTIONS
281

  
282
These functions are called on a controller instance.
283

  
284
=over 4
285

  
286
=item C<get_current_filter_params>
287

  
288
Returns a hash to be used in manager C<get_all> calls or to be passed on to
289
GetModels. Will only work if the get_models chain has been called at least
290
once, because only then the full parameters can get parsed and stored. Will
291
croak otherwise.
292

  
293
=item C<disable_filtering>
294

  
295
Disable filtering for the duration of the current action. Can be used
296
when using the attribute C<ONLY> to L<make_filtered> does not
297
cover all cases.
298

  
299
=back
300

  
301
=head1 BUGS
302

  
303
Nothing here yet.
304

  
305
=head1 AUTHOR
306

  
307
Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
308

  
309
=cut
SL/Controller/Helper/GetModels.pm
2 2

  
3 3
use strict;
4 4

  
5
use Exporter qw(import);
6
our @EXPORT = qw(get_models_url_params get_callback get_models);
5
use parent 'Rose::Object';
6
use SL::Controller::Helper::GetModels::Filtered;
7
use SL::Controller::Helper::GetModels::Sorted;
8
use SL::Controller::Helper::GetModels::Paginated;
9

  
10
use Rose::Object::MakeMethods::Generic (
11
  scalar => [ qw(controller model query with_objects filtered sorted paginated) ],
12
  'scalar --get_set_init' => [ qw(handlers) ],
13
);
7 14

  
8 15
use constant PRIV => '__getmodelshelperpriv';
9 16

  
10
my $registered_handlers = {};
17
#my $registered_handlers = {};
18

  
19
sub init {
20
  my ($self, %params) = @_;
21

  
22
#  for my $plugin (qw(filtered sorted paginated)) {
23
#    next unless $params{$plugin};
24
#    $self->${ \"make_$plugin" }(%{ delete $params{$plugin} || {} });
25
#  }
26
#
27
  # TODO: default model
28
  $self->model(delete $params{model});
29

  
30
  for my $plugin (qw(filtered sorted paginated)) {
31
    next unless my $spec = delete $params{$plugin} // {};
32
    my $plugin_class = "SL::Controller::Helper::GetModels::" . ucfirst $plugin;
33
    $self->$plugin($plugin_class->new(%$spec, get_models => $self));
34
  }
35

  
36
  $self->SUPER::init(%params);
37
}
11 38

  
12
sub register_get_models_handlers {
13
  my ($class, %additional_handlers) = @_;
39
sub register_handlers {
40
  my ($self, %additional_handlers) = @_;
14 41

  
15
  my $only        = delete($additional_handlers{ONLY}) || [];
16
  $only           = [ $only ] if !ref $only;
17
  my %hook_params = @{ $only } ? ( only => $only ) : ();
42
#  my $only        = delete($additional_handlers{ONLY}) || [];
43
#  $only           = [ $only ] if !ref $only;
44
#  my %hook_params = @{ $only } ? ( only => $only ) : ();
18 45

  
19
  my $handlers    = _registered_handlers($class);
46
  my $handlers    = $self->handlers;
20 47
  map { push @{ $handlers->{$_} }, $additional_handlers{$_} if $additional_handlers{$_} } keys %$handlers;
21 48
}
22 49

  
......
39 66
sub get_callback {
40 67
  my ($self, %override_params) = @_;
41 68

  
42
  my %default_params = _run_handlers($self, 'callback', action => $self->action_name);
69
  my %default_params = $self->_run_handlers('callback', action => $self->controller->action_name);
43 70

  
44
  return $self->url_for(%default_params, %override_params);
71
  return $self->controller->url_for(%default_params, %override_params);
45 72
}
46 73

  
47
sub get_models {
48
  my ($self, %override_params) = @_;
74
sub get {
75
  my ($self, %params) = @_;
76

  
77
  push @{ $params{query}        ||= [] }, @{ $self->query || [] };
78
  push @{ $params{with_objects} ||= [] }, @{ $self->with_objects || [] };
79

  
80
  %params                      = $self->_run_handlers('get_models', %params);
81

  
82
  return $self->manager->get_all(%params);
83
}
84

  
85
sub get_paginate_args {
86
  my ($self, %params) = @_;
49 87

  
50
  my %params                   = _run_handlers($self, 'get_models', %override_params);
88
  push @{ $params{query}        ||= [] }, @{ $self->query || [] };
89
  push @{ $params{with_objects} ||= [] }, @{ $self->with_objects || [] };
51 90

  
52
  my $model                    = delete($params{model}) || die "No 'model' to work on";
91
  $self->paginated->get_current_paginate_params(%params);
92
}
53 93

  
54
  return "SL::DB::Manager::${model}"->get_all(%params);
94
sub manager {
95
  die "No 'model' to work on" unless $_[0]->model;
96
  "SL::DB::Manager::" . $_[0]->model;
55 97
}
56 98

  
57 99
#
......
61 103
sub _run_handlers {
62 104
  my ($self, $handler_type, %params) = @_;
63 105

  
64
  foreach my $sub (@{ _registered_handlers(ref $self)->{$handler_type} }) {
106
  foreach my $sub (@{ $self->handlers->{$handler_type} }) {
65 107
    if (ref $sub eq 'CODE') {
66 108
      %params = $sub->($self, %params);
67 109
    } elsif ($self->can($sub)) {
......
74 116
  return %params;
75 117
}
76 118

  
77
sub _registered_handlers {
78
  $registered_handlers->{$_[0]} //= { callback => [], get_models => [] }
119
sub init_handlers {
120
  {
121
    callback => [],
122
    get_models => [],
123
  }
79 124
}
80 125

  
81 126
1;
SL/Controller/Helper/GetModels/Base.pm
1
package SL::Controller::Helper::GetModels::Base;
2

  
3
use strict;
4
use parent 'Rose::Object';
5
use Scalar::Util qw(weaken);
6

  
7

  
8
use Rose::Object::MakeMethods::Generic (
9
  scalar => [ qw(get_models) ],
10
);
11

  
12
sub set_get_models {
13
  $_[0]->get_models($_[1]);
14

  
15
  weaken($_[1]);
16
}
17

  
18
sub merge_args {
19
  my ($self, @args) = @_;
20
  my $final_args = { };
21

  
22
  for my $field (qw(query with_objects)) {
23
    $final_args->{$field} = [ map { @{ $_->{$field} || [] } } @args ];
24
  }
25

  
26
  return %$final_args;
27
}
28

  
29
1;
SL/Controller/Helper/GetModels/Filtered.pm
1
package SL::Controller::Helper::GetModels::Filtered;
2

  
3
use strict;
4
use parent 'SL::Controller::Helper::GetModels::Base';
5

  
6
use Exporter qw(import);
7
use SL::Controller::Helper::ParseFilter ();
8
use List::MoreUtils qw(uniq);
9

  
10
use Rose::Object::MakeMethods::Generic (
11
  scalar => [ qw(disabled filter_args filter_params) ],
12
  'scalar --get_set_init' => [ qw(form_params launder_to) ],
13
);
14

  
15
sub init {
16
  my ($self, %specs)             = @_;
17

  
18
  $self->set_get_models(delete $specs{get_models});
19
  $self->SUPER::init(%specs);
20

  
21
  $self->get_models->register_handlers(
22
    callback   => sub { shift; $self->_callback_handler_for_filtered(@_) },
23
    get_models => sub { shift; $self->_get_models_handler_for_filtered(@_) },
24
  );
25

  
26
  # $::lxdebug->dump(0, "CONSPEC", \%specs);
27
}
28

  
29
sub get_current_filter_params {
30
  my ($self)   = @_;
31

  
32
  return $self->filter_params if $self->filter_params;
33

  
34
  require Carp;
35
  Carp::confess('It seems a GetModels plugin tries to access filter params before they got calculated. Make sure your make_filtered call comes first.');
36
}
37

  
38
sub _make_current_filter_params {
39
  my ($self, %params)   = @_;
40

  
41
#  my $spec              = $self->get_filter_spec;
42
  my $filter            = $params{filter} // $::form->{ $self->form_params } // {},
43
  my %filter_args       = $self->_get_filter_args;
44
  my %parse_filter_args = (
45
    class        => $self->get_models->manager,
46
    with_objects => $params{with_objects},
47
  );
48
  my $laundered;
49
  if ($self->launder_to eq '__INPLACE__') {
50
    # nothing to do
51
  } elsif ($self->launder_to) {
52
    $laundered = {};
53
    $parse_filter_args{launder_to} = $laundered;
54
  } else {
55
    $parse_filter_args{no_launder} = 1;
56
  }
57

  
58
  my %calculated_params = SL::Controller::Helper::ParseFilter::parse_filter($filter, %parse_filter_args);
59
  %calculated_params = $self->merge_args(\%calculated_params, \%filter_args, \%params);
60

  
61
#  $calculated_params{query} = [
62
#    @{ $calculated_params{query} || [] },
63
#    @{ $filter_args{      query} || [] },
64
#    @{ $params{           query} || [] },
65
#  ];
66
#
67
#  $calculated_params{with_objects} = [
68
#    uniq
69
#    @{ $calculated_params{with_objects} || [] },
70
#    @{ $filter_args{      with_objects} || [] },
71
#    @{ $params{           with_objects} || [] },
72
#  ];
73

  
74
  if ($laundered) {
75
    if ($self->get_models->controller->can($self->launder_to)) {
76
      $self->get_models->controller->${\ $self->launder_to }($laundered);
77
    } else {
78
      $self->get_models->controller->{$self->launder_to} = $laundered;
79
    }
80
  }
81

  
82
  # $::lxdebug->dump(0, "get_current_filter_params: ", \%calculated_params);
83

  
84
  $self->filter_params(\%calculated_params);
85

  
86
  return %calculated_params;
87
}
88

  
89
sub disable_filtering {
90
  my ($self)               = @_;
91
  $self->disabled(1);
92
}
93

  
94
#
95
# private functions
96
#
97

  
98
sub _get_filter_args {
99
  my ($self, $spec) = @_;
100

  
101
  my %filter_args   = ref($self->filter_args) eq 'CODE' ? %{ $self->filter_args->($self) }
102
                    :     $self->filter_args            ? do { my $sub = $self->filter_args; %{ $self->get_models->controller->$sub() } }
103
                    :                                       ();
104
}
105

  
106
sub _callback_handler_for_filtered {
107
  my ($self, %params) = @_;
108

  
109
  if ($self->is_enabled) {
110
    my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($::form->{ $self->form_params }, $self->form_params);
111
    %params         = (%params, @{ $flattened || [] });
112
  }
113

  
114
  # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
115

  
116
  return %params;
117
}
118

  
119
sub _get_models_handler_for_filtered {
120
  my ($self, %params)    = @_;
121

  
122
  # $::lxdebug->dump(0,  "params in get_models_for_filtered", \%params);
123

  
124
  my %filter_params;
125
  %filter_params = $self->_make_current_filter_params(%params)  if $self->is_enabled;
126

  
127
  # $::lxdebug->dump(0, "GM handler for filtered; params nach modif (is_enabled? " . $self->is_enabled . ")", \%params);
128

  
129
  return (%params, %filter_params);
130
}
131

  
132
sub is_enabled {
133
  !$_[0]->disabled;
134
}
135

  
136
sub init_form_params {
137
  'filter'
138
}
139

  
140
sub init_launder_to {
141
  'filter'
142
}
143

  
144

  
145
1;
146

  
147
__END__
148

  
149
=pod
150

  
151
=encoding utf8
152

  
153
=head1 NAME
154

  
155
SL::Controller::Helper::Filtered - A helper for semi-automatic handling
156
of filtered lists of database models in a controller
157

  
158
=head1 SYNOPSIS
159

  
160
In a controller:
161

  
162
  use SL::Controller::Helper::GetModels;
163
  use SL::Controller::Helper::Filtered;
164

  
165
  __PACKAGE__->make_filter(
166
    MODEL       => 'Part',
167
    ONLY        => [ qw(list) ],
168
    FORM_PARAMS => [ qw(filter) ],
169
  );
170

  
171
  sub action_list {
172
    my ($self) = @_;
173

  
174
    my $filtered_models = $self->get_models(%addition_filters);
175
    $self->render('controller/list', ENTRIES => $filtered_models);
176
  }
177

  
178

  
179
=head1 OVERVIEW
180

  
181
This helper module enables use of the L<SL::Controller::Helper::ParseFilter>
182
methods in conjunction with the L<SL::Controller::Helper::GetModels> style of
183
plugins. Additional filters can be defined in the database models and filtering
184
can be reduced to a minimum of work.
185

  
186
This plugin can be combined with L<SL::Controller::Sorted> and
187
L<SL::Controller::Paginated> for filtered, sorted and paginated lists.
188

  
189
The controller has to provive information where to look for filter information
190
at compile time. This call is L<make_filtered>.
191

  
192
The underlying functionality that enables the use of more than just
193
the paginate helper is provided by the controller helper
194
C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
195
more information on it.
196

  
197
=head1 PACKAGE FUNCTIONS
198

  
199
=over 4
200

  
201
=item C<make_filtered %filter_spec>
202

  
203
This function must be called by a controller at compile time. It is
204
uesd to set the various parameters required for this helper to do its
205
magic.
206

  
207
Careful: If you want to use this in conjunction with
208
L<SL:Controller::Helper::Paginated>, you need to call C<make_filtered> first,
209
or the paginating will not get all the relevant information to estimate the
210
number of pages correctly. To ensure this does not happen, this module will
211
croak when it detects such a scenario.
212

  
213
The hash C<%filter_spec> can include the following parameters:
214

  
215
=over 4
216

  
217
=item * C<MODEL>
218

  
219
Optional. A string: the name of the Rose database model that is used
220
as a default in certain cases. If this parameter is missing then it is
221
derived from the controller's package (e.g. for the controller
222
C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
223
C<BackgroundJobHistory>).
224

  
225
=item * C<FORM_PARAMS>
226

  
227
Optional. Indicates a key in C<$::form> to be used as filter.
228

  
229
Defaults to the values C<filter> if missing.
230

  
231
=item * C<LAUNDER_TO>
232

  
233
Option. Indicates a target for laundered filter arguments in the controller.
234
Can be set to C<undef> to disable laundering, and can be set to method named or
235
hash keys of the controller. In the latter case the laundered structure will be
236
put there.
237

  
238
Defaults to inplace laundering which is not normally settable.
239

  
240
=item * C<ONLY>
241

  
242
Optional. An array reference containing a list of action names for
243
which the paginate parameters should be saved. If missing or empty then
244
all actions invoked on the controller are monitored.
245

  
246
=back
247

  
248
=back
249

  
250
=head1 INSTANCE FUNCTIONS
251

  
252
These functions are called on a controller instance.
253

  
254
=over 4
255

  
256
=item C<get_current_filter_params>
257

  
258
Returns a hash to be used in manager C<get_all> calls or to be passed on to
259
GetModels. Will only work if the get_models chain has been called at least
260
once, because only then the full parameters can get parsed and stored. Will
261
croak otherwise.
262

  
263
=item C<disable_filtering>
264

  
265
Disable filtering for the duration of the current action. Can be used
266
when using the attribute C<ONLY> to L<make_filtered> does not
267
cover all cases.
268

  
269
=back
270

  
271
=head1 BUGS
272

  
273
Nothing here yet.
274

  
275
=head1 AUTHOR
276

  
277
Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
278

  
279
=cut
SL/Controller/Helper/GetModels/Paginated.pm
1
package SL::Controller::Helper::GetModels::Paginated;
2

  
3
use strict;
4
use parent 'SL::Controller::Helper::GetModels::Base';
5

  
6
use List::Util qw(min);
7

  
8
use Rose::Object::MakeMethods::Generic (
9
  scalar => [ qw(disabled per_page) ],
10
  'scalar --get_set_init' => [ qw(form_params paginate_args) ],
11
);
12

  
13
sub init {
14
  my ($self, %specs)               = @_;
15

  
16
  $self->set_get_models(delete $specs{get_models});
17
  $self->SUPER::init(%specs);
18

  
19
  $self->per_page($self->get_models->manager->default_objects_per_page) unless $self->per_page;
20

  
21
  $self->get_models->register_handlers(
22
    callback   => sub { shift; $self->_callback_handler_for_paginated(@_) },
23
    get_models => sub { shift; $self->_get_models_handler_for_paginated(@_) },
24
  );
25

  
26
  # $::lxdebug->dump(0, "CONSPEC", \%specs);
27
}
28

  
29
sub get_current_paginate_params {
30
  my ($self, %args)   = @_;
31
  return () unless $self->is_enabled;
32

  
33
  my %paginate_params = $self->final_params(%args);
34

  
35
  # try to use Filtered if available and nothing else is configured, but don't
36
  # blow up if the controller does not use Filtered
37
  my %paginate_args     = ref($self->paginate_args) eq 'CODE'       ? %{ $self->paginate_args->($self) }
38
                        :     $self->paginate_args  eq '__FILTER__'
39
                           && $self->get_models->filtered ? %{ $self->get_models->filtered->get_current_filter_params }
40
                        :     $self->paginate_args  ne '__FILTER__' ? do { my $sub = $self->paginate_args; %{ $self->get_models->controller->$sub() } }
41
                        :                                               ();
42

  
43
  %args = $self->merge_args(\%args, \%paginate_args);
44

  
45
  my $calculated_params = $self->get_models->manager->paginate(%paginate_params, args => \%args);
46

  
47
  # $::lxdebug->dump(0, "get_current_paginate_params: ", $calculated_params);
48

  
49
  return %{ $calculated_params };
50
}
51

  
52
sub disable_pagination {
53
  my ($self)               = @_;
54
  $self->disabled(1);
55
}
56

  
57
sub final_params {
58
  my ($self, %params)      = @_;
59

  
60
  my $from_form = {
61
    page            => $::form->{ $self->form_params->[0] } || 1,
62
    per_page        => $::form->{ $self->form_params->[1] } * 1,
63
  };
64

  
65
#  my $priv              = _priv($self);
66
  $params{page}         = $from_form->{page}     unless defined $params{page};
67
  $params{per_page}     = $from_form->{per_page} unless defined $params{per_page};
68

  
69
  $params{page}         = ($params{page} * 1) || 1;
70
  $params{per_page}     = ($params{per_page} * 1) || $self->per_page;
71

  
72
  %params;
73
}
74

  
75
#
76
# private functions
77
#
78

  
79
sub init_form_params {
80
  [ qw(page per_page) ]
81
}
82

  
83
sub init_paginate_args {
84
  '__FILTER__'
85
}
86

  
87
sub _callback_handler_for_paginated {
88
  my ($self, %params) = @_;
89
  my %form_params = $self->final_params;
90
#  my $priv            = _priv($self);
91

  
92
  if ($self->is_enabled && $form_params{page}) {
93
    $params{ $self->form_params->[0] } = $form_params{page};
94
    $params{ $self->form_params->[1] } = $form_params{per_page} if $form_params{per_page};
95
  }
96

  
97
  # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
98

  
99
  return %params;
100
}
101

  
102
sub _get_models_handler_for_paginated {
103
  my ($self, %params)    = @_;
104

  
105
  $self->get_models->manager->paginate($self->final_params, args => \%params) if $self->is_enabled;
106

  
107
  # $::lxdebug->dump(0, "GM handler for paginated; params nach modif (is_enabled? " . _is_enabled($self) . ")", \%params);
108

  
109
  return %params;
110
}
111

  
112
sub is_enabled {
113
  my ($self) = @_;
114
  return !$self->disabled;
115
}
116

  
117
1;
118
__END__
119

  
120
=pod
121

  
122
=encoding utf8
123

  
124
=head1 NAME
125

  
126
SL::Controller::Helper::Paginated - A helper for semi-automatic handling
127
of paginating lists of database models in a controller
128

  
129
=head1 SYNOPSIS
130

  
131
In a controller:
132

  
133
  use SL::Controller::Helper::GetModels;
134
  use SL::Controller::Helper::Paginated;
135

  
136
  __PACKAGE__->make_paginated(
137
    MODEL       => 'BackgroundJobHistory',
138
    ONLY        => [ qw(list) ],
139
    FORM_PARAMS => [ qw(page per_page) ],
140
  );
141

  
142
  sub action_list {
143
    my ($self) = @_;
144

  
145
    my $paginated_models = $self->get_models;
146
    $self->render('controller/list', ENTRIES => $paginated_models);
147
  }
148

  
149
In said template:
150

  
151
  [% USE L %]
152

  
153
  <table>
154
   <thead>
155
    <tr>
156
     ...
157
    </tr>
158
   </thead>
159

  
160
   <tbody>
161
    [% FOREACH entry = ENTRIES %]
162
     <tr>
163
      ...
164
     </tr>
165
    [% END %]
166
   </tbody>
167
  </table>
168

  
169
  [% L.paginate_controls %]
170

  
171
=head1 OVERVIEW
172

  
173
This specialized helper module enables controllers to display a
174
paginatable list of database models with as few lines as possible. It
175
can also be combined trivially with the L<SL::Controller::Sorted>
176
helper for sortable lists.
177

  
178
For this to work the controller has to provide the information which
179
indexes are eligible for paginateing etc. by a call to
180
L<make_paginated> at compile time.
181

  
182
The underlying functionality that enables the use of more than just
183
the paginate helper is provided by the controller helper
184
C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
185
more information on it.
186

  
187
A template can use the method C<paginate_controls> from the layout
188
helper module C<L> which renders the links for navigation between the
189
pages.
190

  
191
This module requires that the Rose model managers use their C<Paginated>
192
helper.
193

  
194
The C<Paginated> helper hooks into the controller call to the action via
195
a C<run_before> hook. This is done so that it can remember the paginate
196
parameters that were used in the current view.
197

  
198
=head1 PACKAGE FUNCTIONS
199

  
200
=over 4
201

  
202
=item C<make_paginated %paginate_spec>
203

  
204
This function must be called by a controller at compile time. It is
205
uesd to set the various parameters required for this helper to do its
206
magic.
207

  
208
The hash C<%paginate_spec> can include the following parameters:
209

  
210
=over 4
211

  
212
=item * C<MODEL>
213

  
214
Optional. A string: the name of the Rose database model that is used
215
as a default in certain cases. If this parameter is missing then it is
216
derived from the controller's package (e.g. for the controller
217
C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
218
C<BackgroundJobHistory>).
219

  
220
=item * C<PAGINATE_ARGS>
221

  
222
Optional. Either a code reference or the name of function to be called
223
on the controller importing this helper.
224

  
225
If this funciton is given then the paginate helper calls it whenever
226
it has to count the total number of models for calculating the number
227
of pages to display. The function must return a hash reference with
228
elements suitable for passing to a Rose model manager's C<get_all>
229
function.
230

  
231
This can be used e.g. when filtering is used.
232

  
233
=item * C<PER_PAGE>
234

  
235
Optional. An integer: the number of models to return per page.
236

  
237
Defaults to the underlying database model's default number of models
238
per page.
239

  
240
=item * C<FORM_PARAMS>
241

  
242
Optional. An array reference with exactly two strings that name the
243
indexes in C<$::form> in which the current page's number (the first
244
element in the array) and the number of models per page (the second
245
element in the array) are stored.
246

  
247
Defaults to the values C<page> and C<per_page> if missing.
248

  
249
=item * C<ONLY>
250

  
251
Optional. An array reference containing a list of action names for
252
which the paginate parameters should be saved. If missing or empty then
253
all actions invoked on the controller are monitored.
254

  
255
=back
256

  
257
=back
258

  
259
=head1 INSTANCE FUNCTIONS
260

  
261
These functions are called on a controller instance.
262

  
263
=over 4
264

  
265
=item C<get_paginate_spec>
266

  
267
Returns a hash containing the currently active paginate
268
parameters. The following keys are returned:
269

  
270
=over 4
271

  
272
=item * C<page>
273

  
274
The currently active page number (numbering starts at 1).
275

  
276
=item * C<per_page>
277

  
278
Number of models per page (at least 1).
279

  
280
=item * C<num_pages>
281

  
282
Number of pages to display (at least 1).
283

  
284
=item * C<common_pages>
285

  
286
An array reference with one hash reference for each possible
287
page. Each hash ref contains the keys C<active> (C<1> if that page is
288
the currently active page), C<page> (the page number this hash
289
reference describes) and C<visible> (whether or not it should be
290
displayed).
291

  
292
=back
293

  
294
=item C<get_current_paginate_params>
295

  
296
Returns a hash reference to the paginate spec structure given in the call
297
to L<make_paginated> after normalization (hash reference construction,
298
applying default parameters etc).
299

  
300
=item C<disable_pagination>
301

  
302
Disable pagination for the duration of the current action. Can be used
303
when using the attribute C<ONLY> to L<make_paginated> does not
304
cover all cases.
305

  
306
=back
307

  
308
=head1 BUGS
309

  
310
Nothing here yet.
311

  
312
=head1 AUTHOR
313

  
314
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
315

  
316
=cut
SL/Controller/Helper/GetModels/Sorted.pm
1
package SL::Controller::Helper::GetModels::Sorted;
2

  
3
use strict;
4
use parent 'SL::Controller::Helper::GetModels::Base';
5

  
6
use Carp;
7
use List::MoreUtils qw(uniq);
8

  
9
use Rose::Object::MakeMethods::Generic (
10
  scalar => [ qw(by dir specs) ],
11
  'scalar --get_set_init' => [ qw(form_params) ],
12
);
13

  
14
sub init {
15
  my ($self, %specs) = @_;
16

  
17
  $self->set_get_models(delete $specs{get_models});
18
  my %model_sort_spec   = $self->get_models->manager->_sort_spec;
19

  
20
  if (my $default = delete $specs{_default}) {
21
    $self->by ($default->{by});
22
    $self->dir($default->{dir});
23
  } else {
24
    $self->by ($model_sort_spec{default}[0]);
25
    $self->dir($model_sort_spec{default}[1]);
26
  }
27

  
28
  while (my ($column, $spec) = each %specs) {
29
    next if $column =~ m/^[A-Z_]+$/;
30

  
31
    $spec = $specs{$column} = { title => $spec } if (ref($spec) || '') ne 'HASH';
32

  
33
    $spec->{model}        ||= $self->get_models->model;
34
    $spec->{model_column} ||= $column;
35
  }
36
  $self->specs(\%specs);
37

  
38
  $self->get_models->register_handlers(
39
    callback   => sub { shift; $self->_callback_handler_for_sorted(@_) },
40
    get_models => sub { shift; $self->_get_models_handler_for_sorted(@_) },
41
  );
42

  
43
#   $::lxdebug->dump(0, "CONSPEC", \%specs);
44
}
45

  
46
sub get_current_sort_params {
47
  my ($self, %params) = @_;
48

  
49
  my %sort_params;
50
  my ($by, $dir) = @{ $self->form_params };
51

  
52
  if ($::form->{ $by }) {
53
    %sort_params = (
54
      sort_by  => $::form->{$by},
55
      sort_dir => defined($::form->{$dir}) ? $::form->{$dir} * 1 : undef,
56
    );
57
  } elsif (!$self->by) {
58
    %sort_params = %params;
59
  } else {
60
    %sort_params = (
61
      sort_by  => $self->by,
62
      sort_dir => $self->dir,
63
    );
64
  }
65

  
66
  return %sort_params;
67
}
68

  
69
sub set_report_generator_sort_options {
70
  my ($self, %params) = @_;
71

  
72
  $params{$_} or croak("Missing parameter '$_'") for qw(report sortable_columns);
73

  
74
  my %current_sort_params = $self->get_current_sort_params;
75

  
76
  foreach my $col (@{ $params{sortable_columns} }) {
77
    $params{report}->{columns}->{$col}->{link} = $self->get_models->get_callback(
78
      sort_by  => $col,
79
      sort_dir => ($current_sort_params{sort_by} eq $col ? 1 - $current_sort_params{sort_dir} : $current_sort_params{sort_dir}),
80
    );
81
  }
82

  
83
  $params{report}->set_sort_indicator($current_sort_params{sort_by}, 1 - $current_sort_params{sort_dir});
84

  
85
  if ($params{report}->{export}) {
86
    $params{report}->{export}->{variable_list} = [ uniq(
87
      @{ $params{report}->{export}->{variable_list} },
88
      @{ $self->form_params }
89
    )];
90
  }
91
}
92

  
93
#
94
# private functions
95
#
96

  
97
sub _callback_handler_for_sorted {
98
  my ($self, %params) = @_;
99
  my %spec = $self->get_current_sort_params;
100

  
101
  if ($spec{sort_by}) {
102
    $params{ $self->form_params->[0] } = $spec{sort_by};
103
    $params{ $self->form_params->[1] } = $spec{sort_dir};
104
  }
105

  
106
  # $::lxdebug->dump(0, "CB handler for sorted; params nach modif:", \%params);
107

  
108
  return %params;
109
}
110

  
111
sub _get_models_handler_for_sorted {
112
  my ($self, %params) = @_;
113

  
114
  my %sort_params     = $self->get_current_sort_params;
115
  my $sort_spec       = $self->specs->{ $sort_params{sort_by} };
116

  
117
  $params{sort_by}    = "SL::DB::Manager::$sort_spec->{model}"->make_sort_string(sort_by => $sort_spec->{model_column}, sort_dir => $sort_params{sort_dir});
118

  
119
  # $::lxdebug->dump(0, "GM handler for sorted; params nach modif:", \%params);
120

  
121
  return %params;
122
}
123

  
124

  
125
sub init_form_params {
126
  [ qw(sort_by sort_dir) ]
127
}
128

  
129
1;
130
__END__
131

  
132
=pod
133

  
134
=encoding utf8
135

  
136
=head1 NAME
137

  
138
SL::Controller::Helper::Sorted - A helper for semi-automatic handling
139
of sorting lists of database models in a controller
140

  
141
=head1 SYNOPSIS
142

  
143
In a controller:
144

  
145
  use SL::Controller::Helper::GetModels;
146
  use SL::Controller::Helper::Sorted;
147

  
148
  __PACKAGE__->make_sorted(
149
    DEFAULT_BY   => 'run_at',
150
    DEFAULT_DIR  => 1,
151
    MODEL        => 'BackgroundJobHistory',
152
    ONLY         => [ qw(list) ],
153

  
154
    error        => $::locale->text('Error'),
155
    package_name => $::locale->text('Package name'),
156
    run_at       => $::locale->text('Run at'),
157
  );
158

  
159
  sub action_list {
160
    my ($self) = @_;
161

  
162
    my $sorted_models = $self->get_models;
163
    $self->render('controller/list', ENTRIES => $sorted_models);
164
  }
165

  
166
In said template:
167

  
168
  [% USE L %]
169

  
170
  <table>
171
   <tr>
172
    <th>[% L.sortable_table_header('package_name') %]</th>
173
    <th>[% L.sortable_table_header('run_at') %]</th>
174
    <th>[% L.sortable_table_header('error') %]</th>
175
   </tr>
176

  
177
   [% FOREACH entry = ENTRIES %]
178
    <tr>
179
     <td>[% HTML.escape(entry.package_name) %]</td>
180
     <td>[% HTML.escape(entry.run_at) %]</td>
181
     <td>[% HTML.escape(entry.error) %]</td>
182
    </tr>
183
   [% END %]
184
  </table>
185

  
186
=head1 OVERVIEW
187

  
188
This specialized helper module enables controllers to display a
189
sortable list of database models with as few lines as possible.
190

  
191
For this to work the controller has to provide the information which
192
indexes are eligible for sorting etc. by a call to L<make_sorted> at
193
compile time.
194

  
195
The underlying functionality that enables the use of more than just
196
the sort helper is provided by the controller helper C<GetModels>. It
197
provides mechanisms for helpers like this one to hook into certain
198
calls made by the controller (C<get_callback> and C<get_models>) so
199
that the specialized helpers can inject their parameters into the
200
calls to e.g. C<SL::DB::Manager::SomeModel::get_all>.
201

  
202
A template on the other hand can use the method
203
C<sortable_table_header> from the layout helper module C<L>.
204

  
205
This module requires that the Rose model managers use their C<Sorted>
206
helper.
207

  
208
The C<Sorted> helper hooks into the controller call to the action via
209
a C<run_before> hook. This is done so that it can remember the sort
210
parameters that were used in the current view.
211

  
212
=head1 PACKAGE FUNCTIONS
213

  
214
=over 4
215

  
216
=item C<make_sorted %sort_spec>
217

  
218
This function must be called by a controller at compile time. It is
219
uesd to set the various parameters required for this helper to do its
220
magic.
221

  
222
There are two sorts of keys in the hash C<%sort_spec>. The first kind
223
is written in all upper-case. Those parameters are control
224
parameters. The second kind are all lower-case and represent indexes
225
that can be used for sorting (similar to database column names). The
226
second kind are also the indexes you use in a template when calling
227
C<[% L.sorted_table_header(...) %]>.
228

  
229
Control parameters include the following:
230

  
231
=over 4
232

  
233
=item * C<MODEL>
234

  
235
Optional. A string: the name of the Rose database model that is used
236
as a default in certain cases. If this parameter is missing then it is
237
derived from the controller's package (e.g. for the controller
238
C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
239
C<BackgroundJobHistory>).
240

  
241
=item * C<DEFAULT_BY>
242

  
243
Optional. A string: the index to sort by if the user hasn't clicked on
244
any column yet (meaning: if the C<$::form> parameters for sorting do
245
not contain a valid index).
246

  
247
Defaults to the underlying database model's default sort column name.
248

  
249
=item * C<DEFAULT_DIR>
250

  
251
Optional. Default sort direction (ascending for trueish values,
252
descrending for falsish values).
253

  
254
Defaults to the underlying database model's default sort direction.
255

  
256
=item * C<FORM_PARAMS>
257

  
258
Optional. An array reference with exactly two strings that name the
259
indexes in C<$::form> in which the sort index (the first element in
260
the array) and sort direction (the second element in the array) are
261
stored.
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff