95 |
95 |
my @result;
|
96 |
96 |
for (my $i = 0; $i < scalar @$flattened; $i += 2) {
|
97 |
97 |
my ($key, $value) = ($flattened->[$i], $flattened->[$i+1]);
|
|
98 |
|
98 |
99 |
($key, $value) = _apply_all($key, $value, qr/\b:(\w+)/, { %filters, %{ $params{filters} || {} } });
|
99 |
100 |
($key, $value) = _apply_all($key, $value, qr/\b::(\w+)/, { %methods, %{ $params{methods} || {} } });
|
|
101 |
($key, $value) = _dispatch_custom_filters($params{class}, $key, $value) if $params{class};
|
|
102 |
|
100 |
103 |
push @result, $key, $value;
|
101 |
104 |
}
|
102 |
105 |
return \@result;
|
103 |
106 |
}
|
104 |
107 |
|
|
108 |
sub _dispatch_custom_filters {
|
|
109 |
my ($class, $key, $value) = @_;
|
|
110 |
|
|
111 |
# the key should by now have no filters left
|
|
112 |
# if it has, catch it here:
|
|
113 |
die 'unrecognized filters' if $key =~ /:/;
|
|
114 |
|
|
115 |
my @tokens = split /\./, $key;
|
|
116 |
my $last_token = pop @tokens;
|
|
117 |
my $curr_class = $class->object_class;
|
|
118 |
|
|
119 |
for my $token (@tokens) {
|
|
120 |
eval {
|
|
121 |
$curr_class = $curr_class->meta->relationship($token)->class;
|
|
122 |
1;
|
|
123 |
} or do {
|
|
124 |
require Carp;
|
|
125 |
Carp::croak("Could not resolve the relationship '$token' in '$key' while building the filter request");
|
|
126 |
}
|
|
127 |
}
|
|
128 |
|
|
129 |
my $manager = $curr_class->meta->convention_manager->auto_manager_class_name;
|
|
130 |
|
|
131 |
if ($manager->can('filter')) {
|
|
132 |
($key, $value) = $manager->filter($last_token, $value, join '.', @tokens, '');
|
|
133 |
}
|
|
134 |
|
|
135 |
return ($key, $value);
|
|
136 |
}
|
|
137 |
|
105 |
138 |
sub _collapse_indirect_filters {
|
106 |
139 |
my ($flattened) = @_;
|
107 |
140 |
|
... | ... | |
227 |
260 |
match method suffixes, which are appended with 2 colons. See below for a full
|
228 |
261 |
list of modifiers.
|
229 |
262 |
|
230 |
|
The reason for the method being last is that it is possible to specify the
|
231 |
|
method in another input. Suppose you want a date input and a separate
|
232 |
|
before/after/equal select, you can use the following:
|
233 |
|
|
234 |
|
[% L.date_tag('filter.appointed_date:date', ... ) %]
|
235 |
|
|
236 |
|
and later
|
237 |
|
|
238 |
|
[% L.select_tag('filter.appointed_date::', ... ) %]
|
239 |
|
|
240 |
|
The special empty method will be used to set the method for the previous
|
241 |
|
method-less input.
|
242 |
|
|
243 |
263 |
=back
|
244 |
264 |
|
245 |
265 |
=head1 LAUNDERING
|
... | ... | |
273 |
293 |
'closed => '1',
|
274 |
294 |
}
|
275 |
295 |
|
|
296 |
=head1 INDIRECT FILTER METHODS
|
|
297 |
|
|
298 |
The reason for the method being last is that it is possible to specify the
|
|
299 |
method in another input. Suppose you want a date input and a separate
|
|
300 |
before/after/equal select, you can use the following:
|
|
301 |
|
|
302 |
[% L.date_tag('filter.appointed_date:date', ... ) %]
|
|
303 |
|
|
304 |
and later
|
|
305 |
|
|
306 |
[% L.select_tag('filter.appointed_date:date::', ... ) %]
|
|
307 |
|
|
308 |
The special empty method will be used to set the method for the previous
|
|
309 |
method-less input.
|
|
310 |
|
|
311 |
=head1 CUSTOM FILTERS FROM OBJECTS
|
|
312 |
|
|
313 |
If the L<parse_filter> call contains a parameter C<class>, custom filters will
|
|
314 |
be honored. Suppose you have added a custom filter 'all' for parts which
|
|
315 |
expands to search both description and partnumber, the following
|
|
316 |
|
|
317 |
$filter = {
|
|
318 |
'part.all:substr::ilike' => 'A1',
|
|
319 |
}
|
|
320 |
|
|
321 |
will expand to:
|
|
322 |
|
|
323 |
query => [
|
|
324 |
or => [
|
|
325 |
part.description => { ilike => '%A1%' },
|
|
326 |
part.partnumber => { ilike => '%A1%' },
|
|
327 |
]
|
|
328 |
]
|
|
329 |
|
|
330 |
For more abuot custom filters, see L<SL::DB::Helper::Filtered>.
|
|
331 |
|
276 |
332 |
=head1 FILTERS (leading with :)
|
277 |
333 |
|
278 |
334 |
The following filters are built in, and can be used.
|
... | ... | |
334 |
390 |
L.input_tag('customer.name:substr::ilike', ...)
|
335 |
391 |
L.input_tag('invoice.customer.name:substr::ilike', ...)
|
336 |
392 |
|
337 |
|
This will sarch for orders whoe invoice has the _same_ customer, which matches
|
|
393 |
This will sarch for orders whose invoice has the _same_ customer, which matches
|
338 |
394 |
both inputs. This is because tables are aliased by their name and not by their
|
339 |
395 |
position in with_objects.
|
340 |
396 |
|
ParseFilter auf Objektdispatch erweitert