X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FController%2FHelper%2FParseFilter.pm;h=37b06737d1935fe8b13d9a8e2a703089ab1c1ceb;hb=17384c044b465c262772eb9737ea298069c4d826;hp=ea4eba0a07300fc4214f6c39821085d99fdfc5c7;hpb=d2550089aa9f5d321e025df59815b0eabc7037ab;p=kivitendo-erp.git diff --git a/SL/Controller/Helper/ParseFilter.pm b/SL/Controller/Helper/ParseFilter.pm index ea4eba0a0..37b06737d 100644 --- a/SL/Controller/Helper/ParseFilter.pm +++ b/SL/Controller/Helper/ParseFilter.pm @@ -8,7 +8,9 @@ our @EXPORT = qw(parse_filter); use DateTime; 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]) }, @@ -21,6 +23,7 @@ my %filters = ( my %methods = ( enable => sub { ;;;; }, + eq_ignore_empty => sub { ($_[0] // '') eq '' ? () : +{ eq => $_[0] } }, map { # since $_ is an alias it can't be used in a closure. even "".$_ or "$_" # does not work, we need a real copy. @@ -32,13 +35,12 @@ my %methods = ( sub parse_filter { my ($filter, %params) = @_; - my $hint_objects = $params{with_objects} || []; - my $auto_objects = []; + my $objects = $params{with_objects} || []; - my ($flattened, $objects) = flatten($filter, $auto_objects, '', %params); + my ($flattened, $auto_objects) = flatten($filter, '', %params); - if ($params{class}) { - $objects = $hint_objects; + if (!$params{class}) { + _add_uniq($objects, $_) for @$auto_objects; } my $query = _parse_filter($flattened, $objects, %params); @@ -69,19 +71,19 @@ sub _launder_keys { } sub flatten { - my ($filter, $with_objects, $prefix, %params) = @_; + my ($filter, $prefix, %params) = @_; - return (undef, $with_objects) unless 'HASH' eq ref $filter; - $with_objects ||= []; + return (undef, []) unless 'HASH' eq ref $filter; + my $with_objects = []; my @result; while (my ($key, $value) = each %$filter) { next if !defined $value || $value eq ''; # 0 is fine if ('HASH' eq ref $value) { - my ($query, $more_objects) = flatten($value, $with_objects, _prefix($prefix, $key)); - push @result, @$query if $query; - push @$with_objects, _prefix($prefix, $key), ($more_objects ? @$more_objects : ()); + my ($query, $more_objects) = flatten($value, _prefix($prefix, $key)); + push @result, @$query if $query; + _add_uniq($with_objects, $_) for _prefix($prefix, $key), @$more_objects; } else { push @result, _prefix($prefix, $key) => $value; } @@ -100,16 +102,45 @@ sub _parse_filter { my @result; for (my $i = 0; $i < scalar @$flattened; $i += 2) { my ($key, $value) = ($flattened->[$i], $flattened->[$i+1]); + my ($type, $op) = $key =~ m{:(.+)::(.+)}; + + 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); + } - ($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}; - - push @result, $key, $value; + push @result, $key, $value if defined $key; } return \@result; } +sub _apply_value_filters { + my ($key, $value, $type, $op) = @_; + + return ($key, $value) unless $key && $value && $type && $op && (ref($value) eq 'HASH'); + + if (($type eq 'date') && ($op eq 'le')) { + my $date = delete $value->{le}; + $value->{lt} = $date->add(days => 1); + } + + return ($key, $value); +} + sub _dispatch_custom_filters { my ($class, $with_objects, $key, $value) = @_; @@ -136,10 +167,10 @@ sub _dispatch_custom_filters { my $obj_prefix = join '.', @tokens, ''; if ($manager->can('filter')) { - ($key, $value, my $obj) = $manager->filter($last_token, $value, $obj_prefix); - _add_uniq($with_objects, $obj); + ($key, $value, my $obj) = $manager->filter($last_token, $value, $obj_prefix, $obj_path); + _add_uniq($with_objects, $obj) if $obj; } else { - _add_uniq($with_objects, $obj_path); + _add_uniq($with_objects, $obj_path) if $obj_path; } return ($key, $value); @@ -149,7 +180,7 @@ sub _add_uniq { my ($array, $what) = @_; $array //= []; - $array = [ uniq @$array, $what ]; + @$array = (uniq @$array, listify($what)); } sub _collapse_indirect_filters { @@ -383,6 +414,11 @@ Adds "%" at the end of the string. Adds "% .. %" around the search string. +=item eq_ignore_empty + +Ignores this item if it's empty. Otherwise compares it with the +standard SQL C<=> operator. + =back =head2 METHODS (leading with ::)