Doku
[kivitendo-erp.git] / 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(filter_args filter_params orig_filter) ],
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   );
24
25   # $::lxdebug->dump(0, "CONSPEC", \%specs);
26 }
27
28 sub read_params {
29   my ($self, %params)   = @_;
30
31   return %{ $self->filter_params } if $self->filter_params;
32   my $source = $self->get_models->source;
33
34   my $filter            = $params{filter} // $source->{ $self->form_params } // {};
35   $self->orig_filter($filter);
36
37   my %filter_args       = $self->_get_filter_args;
38   my %parse_filter_args = (
39     class        => $self->get_models->manager,
40     with_objects => $params{with_objects},
41   );
42   my $laundered;
43   if ($self->launder_to eq '__INPLACE__') {
44     # nothing to do
45   } elsif ($self->launder_to) {
46     $laundered = {};
47     $parse_filter_args{launder_to} = $laundered;
48   } else {
49     $parse_filter_args{no_launder} = 1;
50   }
51
52   my %calculated_params = SL::Controller::Helper::ParseFilter::parse_filter($filter, %parse_filter_args);
53   %calculated_params = $self->merge_args(\%calculated_params, \%filter_args, \%params);
54
55   if ($laundered) {
56     if ($self->get_models->controller->can($self->launder_to)) {
57       $self->get_models->controller->${\ $self->launder_to }($laundered);
58     } else {
59       $self->get_models->controller->{$self->launder_to} = $laundered;
60     }
61   }
62
63   # $::lxdebug->dump(0, "get_current_filter_params: ", \%calculated_params);
64
65   $self->filter_params(\%calculated_params);
66
67   return %calculated_params;
68 }
69
70 sub finalize {
71   my ($self, %params) = @_;
72
73   my %filter_params;
74   %filter_params = $self->read_params(%params)  if $self->is_enabled;
75
76   # $::lxdebug->dump(0, "GM handler for filtered; params nach modif (is_enabled? " . $self->is_enabled . ")", \%params);
77
78   return $self->merge_args(\%params, \%filter_params);
79 }
80
81 #
82 # private functions
83 #
84
85 sub _get_filter_args {
86   my ($self, $spec) = @_;
87
88   my %filter_args   = ref($self->filter_args) eq 'CODE' ? %{ $self->filter_args->($self) }
89                     :     $self->filter_args            ? do { my $sub = $self->filter_args; %{ $self->get_models->controller->$sub() } }
90                     :                                       ();
91 }
92
93 sub _callback_handler_for_filtered {
94   my ($self, %params) = @_;
95
96   if ($self->is_enabled) {
97     my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($self->orig_filter, $self->form_params);
98     %params         = (%params, @{ $flattened || [] });
99   }
100
101   # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
102
103   return %params;
104 }
105
106 sub init_form_params {
107   'filter'
108 }
109
110 sub init_launder_to {
111   'filter'
112 }
113
114
115 1;
116
117 __END__
118
119 =pod
120
121 =encoding utf8
122
123 =head1 NAME
124
125 SL::Controller::Helper::GetModels::Filtered - Filter handling plugin for GetModels
126
127 =head1 SYNOPSIS
128
129 In a controller:
130
131   SL::Controller::Helper::GetModels->new(
132     ...
133     filtered => {
134       filter      => HASHREF,
135       launder_to  => HASHREF | SUBNAME | '__INPLACE__',
136     }
137
138     OR
139
140     filtered => 0,
141   );
142
143
144 =head1 OVERVIEW
145
146 This C<GetModels> plugin enables use of the
147 L<SL::Controller::Helper::ParseFilter> methods. Additional filters can be
148 defined in the database models and filtering can be reduced to a minimum of
149 work.
150
151 The underlying functionality that enables the use of more than just
152 the paginate helper is provided by the controller helper
153 C<GetModels>. See the documentation for L<SL::Controller::Helper::GetModels> for
154 more information on it.
155
156 =head1 OPTIONS
157
158 =over 4
159
160 =item * C<filter>
161
162 Optional. Indicates a key in C<source> to be used as filter.
163
164 Defaults to the value C<filter> if missing.
165
166 =item * C<launder_to>
167
168 Optional. Indicates a target for laundered filter arguments in the controller.
169 Can be set to C<undef> to disable laundering, and can be set to method named or
170 hash keys of the controller. In the latter case the laundered structure will be
171 put there.
172
173 Defaults to the controller. Laundered values will end up in C<SELF.filter> for
174 template purposes.
175
176 Setting this to the special value C<__INPLACE__> will cause inplace laundering.
177
178 =back
179
180 =head1 FILTER FORMAT
181
182 See L<SL::Controller::Helper::ParseFilter> for a description of the filter format.
183
184 =head1 CUSTOM FILTERS
185
186 C<Filtered> will honor custom filters defined in RDBO managers. See
187 L<SL::DB::Helper::Filtered> for an explanation fo those.
188
189 =head1 BUGS
190
191 =over 4
192
193 =item * There is currently no easy way to filter for CVars.
194
195 =back
196
197 =head1 AUTHOR
198
199 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
200
201 =cut