642d542a00f78f63a4e65c5beababe2c84b2b1c5
[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) ],
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   # $::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 =head1 OVERVIEW
144
145 This C<GetModels> plugin enables use of the
146 L<SL::Controller::Helper::ParseFilter> methods. Additional filters can be
147 defined in the database models and filtering can be reduced to a minimum of
148 work.
149
150 The underlying functionality that enables the use of more than just
151 the paginate helper is provided by the controller helper
152 C<GetModels>. See the documentation for L<SL::Controller::Helper::GetModels> for
153 more information on it.
154
155 =head1 OPTIONS
156
157 =over 4
158
159 =item * C<filter>
160
161 Optional. Indicates a key in C<source> to be used as filter.
162
163 Defaults to the value C<filter> if missing.
164
165 =item * C<launder_to>
166
167 Optional. Indicates a target for laundered filter arguments in the controller.
168 Can be set to C<undef> to disable laundering, and can be set to method named or
169 hash keys of the controller. In the latter case the laundered structure will be
170 put there.
171
172 Defaults to the controller. Laundered values will end up in C<SELF.filter> for
173 template purposes.
174
175 Setting this to the special value C<__INPLACE__> will cause inplace laundering.
176
177 =back
178
179 =head1 FILTER FORMAT
180
181 See L<SL::Controller::Helper::ParseFilter> for a description of the filter format.
182
183 =head1 CUSTOM FILTERS
184
185 C<Filtered> will honor custom filters defined in RDBO managers. See
186 L<SL::DB::Helper::Filtered> for an explanation fo those.
187
188 =head1 BUGS
189
190 =over 4
191
192 =item * There is currently no easy way to filter for CVars.
193
194 =back
195
196 =head1 AUTHOR
197
198 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
199
200 =cut