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;
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 {
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__
=back
+=head1 INSTALLED MANAGER METHODS
+
+=over 4
+
+=item Custom filter for GetModels
+
+If the Manager for the calling C<SL::DB::Object> has included the helper L<SL::DB::Helper::Filtered>, 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 E<lt>s.schoeling@linet-services.deE<gt>,
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 {