X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FController%2FHelper%2FParseFilter.pm;h=afe9b7b51b6d8b582f79e56ee12e48334f788fb9;hb=228dfbdc7b671f8c8ac8254ae7cda2e3675351ae;hp=8ccd83401749d36adc9c5f1adfba30c2a7fcd76a;hpb=1264cff68a2e27855c34fc2e00e1f6724ab004f4;p=kivitendo-erp.git diff --git a/SL/Controller/Helper/ParseFilter.pm b/SL/Controller/Helper/ParseFilter.pm index 8ccd83401..afe9b7b51 100644 --- a/SL/Controller/Helper/ParseFilter.pm +++ b/SL/Controller/Helper/ParseFilter.pm @@ -8,6 +8,7 @@ our @EXPORT = qw(parse_filter); use DateTime; use SL::Helper::DateTime; use List::MoreUtils qw(uniq); +use SL::MoreCommon qw(listify); use Data::Dumper; my %filters = ( @@ -21,6 +22,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,11 +34,15 @@ my %methods = ( sub parse_filter { my ($filter, %params) = @_; - my $hint_objects = $params{with_objects} || []; + my $objects = $params{with_objects} || []; - my ($flattened, $objects) = _pre_parse($filter, $hint_objects, '', %params); + my ($flattened, $auto_objects) = flatten($filter, '', %params); - my $query = _parse_filter($flattened, %params); + if (!$params{class}) { + _add_uniq($objects, $_) for @$auto_objects; + } + + my $query = _parse_filter($flattened, $objects, %params); _launder_keys($filter, $params{launder_to}) unless $params{no_launder}; @@ -55,7 +61,7 @@ sub _launder_keys { if ('' eq ref $filter->{$orig}) { $launder_to->{$key} = $filter->{$orig}; } elsif ('ARRAY' eq ref $filter->{$orig}) { - $launder_to->{$key} = [ @{ $filter->{$orig} } ]; + $launder_to->{"${key}_"} = { map { $_ => 1 } @{ $filter->{$orig} } }; } else { $launder_to->{$key} ||= { }; _launder_keys($filter->{$key}, $launder_to->{$key}); @@ -63,20 +69,20 @@ sub _launder_keys { }; } -sub _pre_parse { - my ($filter, $with_objects, $prefix, %params) = @_; +sub flatten { + 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) = _pre_parse($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; } @@ -86,7 +92,7 @@ sub _pre_parse { } sub _parse_filter { - my ($flattened, %params) = @_; + my ($flattened, $with_objects, %params) = @_; return () unless 'ARRAY' eq ref $flattened; @@ -98,15 +104,15 @@ sub _parse_filter { ($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}, $key, $value) if $params{class}; + ($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 _dispatch_custom_filters { - my ($class, $key, $value) = @_; + my ($class, $with_objects, $key, $value) = @_; # the key should by now have no filters left # if it has, catch it here: @@ -126,15 +132,27 @@ sub _dispatch_custom_filters { } } - my $manager = $curr_class->meta->convention_manager->auto_manager_class_name; + my $manager = $curr_class->meta->convention_manager->auto_manager_class_name; + my $obj_path = join '.', @tokens; + my $obj_prefix = join '.', @tokens, ''; if ($manager->can('filter')) { - ($key, $value) = $manager->filter($last_token, $value, join '.', @tokens, ''); + ($key, $value, my $obj) = $manager->filter($last_token, $value, $obj_prefix); + _add_uniq($with_objects, $obj) if $obj; + } else { + _add_uniq($with_objects, $obj_path) if $obj_path; } return ($key, $value); } +sub _add_uniq { + my ($array, $what) = @_; + + $array //= []; + @$array = (uniq @$array, listify($what)); +} + sub _collapse_indirect_filters { my ($flattened) = @_; @@ -270,15 +288,21 @@ default laundered into underscores, so you can use them like this: [% L.input_tag('filter.price:number::lt', filter.price_number__lt) %] -All of your original entries will stay intactg. If you don't want this to +Also Template has trouble when looking up the contents of arrays, so +these will get copied into a _ suffixed version as hashes: + + [% L.checkbox_tag('filter.ids[]', value=15, checked=filter.ids_.15) %] + +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 -if you have a filter that looks liek this: +if you have a filter that looks like this: $filter = { 'price:number::lt' => '2,30', - 'closed => '1', + closed => '1', + type => [ 'part', 'assembly' ], } and parse it with @@ -290,7 +314,8 @@ like this: $filter = { 'price_number__lt' => '2,30', - 'closed => '1', + closed => '1', + 'type_' => { part => 1, assembly => 1 }, } =head1 INDIRECT FILTER METHODS @@ -359,6 +384,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 ::)