eaf7404611f76817b9ab620132dfe3ea65ec4017
[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 filter) ],
12   'scalar --get_set_init' => [ qw(form_params launder_to laundered) ],
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            = $self->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   # Store laundered result in $self->laundered.
64   $self->laundered($laundered // $filter) unless $parse_filter_args{no_launder};
65
66   # $::lxdebug->dump(0, "get_current_filter_params: ", \%calculated_params);
67
68   $self->filter_params(\%calculated_params);
69
70   return %calculated_params;
71 }
72
73 sub finalize {
74   my ($self, %params) = @_;
75
76   my %filter_params;
77   %filter_params = $self->read_params(%params)  if $self->is_enabled;
78
79   # $::lxdebug->dump(0, "GM handler for filtered; params nach modif (is_enabled? " . $self->is_enabled . ")", \%params);
80
81   return $self->merge_args(\%params, \%filter_params);
82 }
83
84 #
85 # private functions
86 #
87
88 sub _get_filter_args {
89   my ($self, $spec) = @_;
90
91   my %filter_args   = ref($self->filter_args) eq 'CODE' ? %{ $self->filter_args->($self) }
92                     :     $self->filter_args            ? do { my $sub = $self->filter_args; %{ $self->get_models->controller->$sub() } }
93                     :                                       ();
94 }
95
96 sub _callback_handler_for_filtered {
97   my ($self, %params) = @_;
98
99   if ($self->is_enabled) {
100     my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($self->orig_filter, $self->form_params);
101     %params         = (%params, @{ $flattened || [] });
102   }
103
104   # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
105
106   return %params;
107 }
108
109 sub init_form_params {
110   'filter'
111 }
112
113 sub init_launder_to {
114   'filter'
115 }
116
117 sub init_laundered {
118   my ($self) = @_;
119
120   $self->get_models->finalize;
121   return $self->{laundered};
122 }
123
124 1;
125
126 __END__
127
128 =pod
129
130 =encoding utf8
131
132 =head1 NAME
133
134 SL::Controller::Helper::GetModels::Filtered - Filter handling plugin for GetModels
135
136 =head1 SYNOPSIS
137
138 In a controller:
139
140   SL::Controller::Helper::GetModels->new(
141     ...
142     filtered => {
143       filter      => HASHREF,
144       launder_to  => HASHREF | SUBNAME | '__INPLACE__',
145     }
146
147     OR
148
149     filtered => 0,
150   );
151
152 =head1 OVERVIEW
153
154 This C<GetModels> plugin enables use of the
155 L<SL::Controller::Helper::ParseFilter> methods. Additional filters can be
156 defined in the database models and filtering can be reduced to a minimum of
157 work.
158
159 The underlying functionality that enables the use of more than just
160 the paginate helper is provided by the controller helper
161 C<GetModels>. See the documentation for L<SL::Controller::Helper::GetModels> for
162 more information on it.
163
164 =head1 OPTIONS
165
166 =over 4
167
168 =item * C<filter>
169
170 Optional. Indicates a key in C<source> to be used as filter.
171
172 Defaults to the value C<filter> if missing.
173
174 =item * C<launder_to>
175
176 Optional. Indicates a target for laundered filter arguments in the controller.
177 Can be set to C<undef> to disable laundering, and can be set to method named or
178 hash keys of the controller. In the latter case the laundered structure will be
179 put there.
180
181 Defaults to the controller. Laundered values will end up in C<SELF.filter> for
182 template purposes.
183
184 Setting this to the special value C<__INPLACE__> will cause inplace laundering.
185
186 =back
187
188 =head1 FILTER FORMAT
189
190 See L<SL::Controller::Helper::ParseFilter> for a description of the filter format.
191
192 =head1 CUSTOM FILTERS
193
194 C<Filtered> will honor custom filters defined in RDBO managers. See
195 L<SL::DB::Helper::Filtered> for an explanation fo those.
196
197 =head1 FUNCTIONS
198
199 =over 4
200
201 =item C<laundered>
202
203 Finalizes the object (which causes laundering of the filter structure)
204 and returns a hashref of the laundered filter. If the plugin is
205 configured not to launder then C<undef> will be returned.
206
207 =back
208
209 =head1 BUGS
210
211 =over 4
212
213 =item * There is currently no easy way to filter for CVars.
214
215 =back
216
217 =head1 AUTHOR
218
219 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
220
221 =cut