From: Moritz Bunkus Date: Tue, 17 Feb 2015 09:48:45 +0000 (+0100) Subject: GetModels-Filtered: Unterstützung für benutzerdefinierte Variablen X-Git-Tag: release-3.2.1~51^2~13 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=8e405005059d7957a627be4bd145b68fd945ac1d;p=kivitendo-erp.git GetModels-Filtered: Unterstützung für benutzerdefinierte Variablen --- diff --git a/SL/Controller/Helper/ParseFilter.pm b/SL/Controller/Helper/ParseFilter.pm index 491eb63b5..759e146c5 100644 --- a/SL/Controller/Helper/ParseFilter.pm +++ b/SL/Controller/Helper/ParseFilter.pm @@ -149,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, $obj_path); + ($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; diff --git a/SL/DB/CustomVariableConfig.pm b/SL/DB/CustomVariableConfig.pm index 5404ebff8..973e3a836 100644 --- a/SL/DB/CustomVariableConfig.pm +++ b/SL/DB/CustomVariableConfig.pm @@ -103,4 +103,24 @@ sub type_dependent_default_value { return (any { $_ eq $self->default_value } @{ $self->processed_options }) ? $self->default_value : $self->processed_options->[0]; } +sub value_col { + my ($self) = @_; + + my $type = $self->type; + + return { + bool => 'bool_value', + timestamp => 'timestamp_value', + number => 'number_value', + integer => 'number_value', + customer => 'number_value', + vendor => 'number_value', + part => 'number_value', + text => 'text_value', + textfield => 'text_value', + date => 'text_value', + select => 'text_value' + }->{$type}; +} + 1; diff --git a/SL/DB/Helper/CustomVariables.pm b/SL/DB/Helper/CustomVariables.pm index 713685519..4b3f39965 100644 --- a/SL/DB/Helper/CustomVariables.pm +++ b/SL/DB/Helper/CustomVariables.pm @@ -28,6 +28,7 @@ sub import { make_cvar_by_name($caller_package, %params); make_cvar_as_hashref($caller_package, %params); make_cvar_value_parser($caller_package, %params); + make_cvar_custom_filter($caller_package, %params); } sub save_meta_info { @@ -223,6 +224,99 @@ sub _get_primary_key_column { return $column_name; } +sub make_cvar_custom_filter { + my ($caller_package, %params) = @_; + + my $manager = $caller_package->meta->convention_manager->auto_manager_class_name; + + return unless $manager->can('filter'); + + $manager->add_filter_specs( + cvar => sub { + my ($key, $value, $prefix, $config_id) = @_; + my $config = SL::DB::Manager::CustomVariableConfig->find_by(id => $config_id); + + if (!$config) { + die "invalid config_id in $caller_package\::cvar custom filter: $config_id"; + } + + if ($config->module != $params{module}) { + die "invalid config_id in $caller_package\::cvar custom filter: expected module $params{module} - got @{[ $config->module ]}"; + } + + my (%query, %bind_vals); + ($query{customized}, $bind_vals{customized}) = Rose::DB::Object::QueryBuilder::build_select( + dbh => $config->dbh, + select => 'trans_id', + tables => [ 'custom_variables' ], + columns => { custom_variables => [ qw(trans_id config_id text_value number_value bool_value timestamp_value sub_module) ] }, + query => [ + config_id => $config_id, + sub_module => $params{sub_module}, + $config->value_col => $value, + ], + query_is_sql => 1, + ); + + my $conversion = $config->type =~ m{^(?:date|timestamp)$} ? $config->type + : $config->type =~ m{^(?:customer|vendor|part)$} ? 'integer' + : $config->type eq 'bool' ? 'boolean' + : $config->type eq 'number' ? 'numeric' + : ''; + + ($query{config}, $bind_vals{config}) = Rose::DB::Object::QueryBuilder::build_select( + dbh => $config->dbh, + select => 'id', + tables => [ 'custom_variable_configs' ], + columns => { custom_variable_configs => [ qw(id default_value) ] }, + query => [ + id => $config->id, + default_value => $value, + ], + query_is_sql => 1, + ); + + $query{config} =~ s{\bdefault_value\b}{default_value::${conversion}} if $conversion; + + ($query{not_customized}, $bind_vals{not_customized}) = Rose::DB::Object::QueryBuilder::build_select( + dbh => $config->dbh, + select => 'trans_id', + tables => [ 'custom_variables' ], + columns => { custom_variables => [ qw(trans_id config_id sub_module) ] }, + query => [ + config_id => $config_id, + sub_module => $params{sub_module}, + ], + query_is_sql => 1, + ); + + foreach my $key (keys %query) { + # remove rose aliases. query builder sadly is not reentrant, and will reuse the same aliases. :( + $query{$key} =~ s{\bt\d+(?:\.)?\b}{}g; + + # manually inline the values. again, rose doen't know how to handly bind params in subqueries :( + $query{$key} =~ s{\?}{ $config->dbh->quote($_) }xe for @{ $bind_vals{$key} }; + + $query{$key} =~ s{\n}{ }g; + } + + my $qry_config = "EXISTS (" . $query{config} . ")"; + + my @result = ( + 'or' => [ + $prefix . 'id' => [ \$query{customized} ], + and => [ + "!${prefix}id" => [ \$query{not_customized} ], + \$qry_config, + ] + ], + ); + + return @result; + } + ); +} + 1; __END__ @@ -371,6 +465,18 @@ some way then you have to call this function manually. For example: =back +=head1 INSTALLED MANAGER METHODS + +=over 4 + +=item Custom filter for GetModels + +If the Manager for the calling C has included the helper L, a custom filter for cvars will be added to the specs, with the following syntax: + + filter.cvar.$config_id + +=back + =head1 AUTHOR Sven Schöling Es.schoeling@linet-services.deE, diff --git a/SL/DB/Helper/Filtered.pm b/SL/DB/Helper/Filtered.pm index 35329494b..5d18d8e89 100644 --- a/SL/DB/Helper/Filtered.pm +++ b/SL/DB/Helper/Filtered.pm @@ -10,13 +10,13 @@ our @EXPORT = qw (filter add_filter_specs); my %filter_spec; sub filter { - my ($class, $key, $value, $prefix, $path) = @_; + my ($class, $key, $value, $prefix, $path, @additional_tokens) = @_; my $filters = _get_filters($class); return ($prefix . $key, $value, $path) unless $filters->{$key}; - return $filters->{$key}->($key, $value, $prefix); + return $filters->{$key}->($key, $value, $prefix, @additional_tokens); } sub _get_filters {