X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FController%2FHelper%2FParseFilter.pm;h=759e146c57c7b9e2f1d7c3a693a5528c5190bf98;hb=8e405005059d7957a627be4bd145b68fd945ac1d;hp=9b5eb516ea87edf83c87fd5e95d970195ab59f55;hpb=08e4ce1ef5caa3f7007d8c97e9e97ef83378b19a;p=kivitendo-erp.git diff --git a/SL/Controller/Helper/ParseFilter.pm b/SL/Controller/Helper/ParseFilter.pm index 9b5eb516e..759e146c5 100644 --- a/SL/Controller/Helper/ParseFilter.pm +++ b/SL/Controller/Helper/ParseFilter.pm @@ -10,6 +10,7 @@ use SL::Helper::DateTime; use List::MoreUtils qw(uniq); use SL::MoreCommon qw(listify); use Data::Dumper; +use Text::ParseWords; my %filters = ( date => sub { DateTime->from_lxoffice($_[0]) }, @@ -103,10 +104,24 @@ sub _parse_filter { my ($key, $value) = ($flattened->[$i], $flattened->[$i+1]); my ($type, $op) = $key =~ m{:(.+)::(.+)}; - ($key, $value) = _apply_all($key, $value, qr/\b:(\w+)/, { %filters, %{ $params{filters} || {} } }); - ($key, $value) = _apply_all($key, $value, qr/\b::(\w+)/, { %methods, %{ $params{methods} || {} } }); - ($key, $value) = _dispatch_custom_filters($params{class}, $with_objects, $key, $value) if $params{class}; - ($key, $value) = _apply_value_filters($key, $value, $type, $op); + if ($key =~ s/:multi//) { + my @multi; + my $orig_key = $key; + for my $value (parse_line('\s+', 0, $value)) { + ($key, $value) = _apply_all($key, $value, qr/\b:(\w+)/, { %filters, %{ $params{filters} || {} } }); + ($key, $value) = _apply_all($key, $value, qr/\b::(\w+)/, { %methods, %{ $params{methods} || {} } }); + ($key, $value) = _dispatch_custom_filters($params{class}, $with_objects, $key, $value) if $params{class}; + ($key, $value) = _apply_value_filters($key, $value, $type, $op); + push @multi, $key, $value; + $key = $orig_key; + } + ($key, $value) = (and => \@multi); + } else { + ($key, $value) = _apply_all($key, $value, qr/\b:(\w+)/, { %filters, %{ $params{filters} || {} } }); + ($key, $value) = _apply_all($key, $value, qr/\b::(\w+)/, { %methods, %{ $params{methods} || {} } }); + ($key, $value) = _dispatch_custom_filters($params{class}, $with_objects, $key, $value) if $params{class}; + ($key, $value) = _apply_value_filters($key, $value, $type, $op); + } push @result, $key, $value if defined $key; } @@ -134,25 +149,27 @@ sub _dispatch_custom_filters { die 'unrecognized filters' if $key =~ /:/; my @tokens = split /\./, $key; - my $last_token = pop @tokens; my $curr_class = $class->object_class; - for my $token (@tokens) { + # find first token which is not a relationship + my $i = 0; + while ($i < $#tokens) { eval { - $curr_class = $curr_class->meta->relationship($token)->class; - 1; + $curr_class = $curr_class->meta->relationship($tokens[$_])->class; + ++$i; } or do { - require Carp; - Carp::croak("Could not resolve the relationship '$token' in '$key' while building the filter request"); + last; } } my $manager = $curr_class->meta->convention_manager->auto_manager_class_name; - my $obj_path = join '.', @tokens; - my $obj_prefix = join '.', @tokens, ''; + my $obj_path = join '.', @tokens[0..$i-1]; + my $obj_prefix = join '.', @tokens[0..$i-1], ''; + my $key_token = $tokens[$i]; + my @additional_tokens = @tokens[$i+1..$#tokens]; if ($manager->can('filter')) { - ($key, $value, my $obj) = $manager->filter($last_token, $value, $obj_prefix); + ($key, $value, my $obj) = $manager->filter($key_token, $value, $obj_prefix, $obj_path, @additional_tokens); _add_uniq($with_objects, $obj) if $obj; } else { _add_uniq($with_objects, $obj_path) if $obj_path; @@ -242,7 +259,7 @@ SL::Controller::Helper::ParseFilter - Convert a form filter spec into a RDBO get A search filter will usually search for things in relations of the actual search target. A search for sales orders may be filtered by the name of the -customer. L alloes you to search for these by filtering them prefixed with their table: +customer. L allows you to search for these by filtering them prefixed with their table: query => [ 'customer.name' => 'John Doe', @@ -250,7 +267,7 @@ customer. L alloes you to search for these by filtering them p 'orddate' => [ lt => DateTime->today ], ] -Unfortunately, if you specify them in you form as these strings, the form +Unfortunately, if you specify them in your form as these strings, the form parser will convert them into nested structures like this: $::form = bless { @@ -282,7 +299,7 @@ specific L: [% L.select_tag('filter.salesman.id', ...) %] -Additionally you can add modifier to the name to set a certain method: +Additionally you can add a modifier to the name to set a certain method: [% L.input_tag('filter.department.description:substr::ilike', ...) %] @@ -298,7 +315,7 @@ list of modifiers. =head1 LAUNDERING Unfortunately Template cannot parse the postfixes if you want to -rerender the filter. For this reason all colons filter keys are by +rerender the filter. For this reason all colon filter keys are by default laundered into underscores, so you can use them like this: [% L.input_tag('filter.price:number::lt', filter.price_number__lt) %] @@ -311,7 +328,7 @@ these will get copied into a _ suffixed version as hashes: All of your original entries will stay intact. If you don't want this to happen pass C<< no_launder => 1 >> as a parameter. Additionally you can pass a different target for the laundered values with the C parameter. It -takes an hashref and will deep copy all values in your filter to the target. So +takes a hashref and will deep copy all values in your filter to the target. So if you have a filter that looks like this: $filter = { @@ -367,7 +384,7 @@ will expand to: ] ] -For more abuot custom filters, see L. +For more about custom filters, see L. =head1 FILTERS (leading with :) @@ -435,7 +452,7 @@ following will not work as you expect: L.input_tag('customer.name:substr::ilike', ...) L.input_tag('invoice.customer.name:substr::ilike', ...) -This will sarch for orders whose invoice has the _same_ customer, which matches +This will search for orders whose invoice has the _same_ customer, which matches both inputs. This is because tables are aliased by their name and not by their position in with_objects. @@ -445,7 +462,7 @@ position in with_objects. =item * -Additional filters shoud be pluggable. +Additional filters should be pluggable. =back