Merge branch 'master' of git.freeside.biz:/home/git/freeside
[freeside.git] / rt / lib / RT / CustomFieldValues / External.pm
index bd60674..66e798a 100644 (file)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -77,12 +77,14 @@ the identifier by which the user will see the dropdown.
 =head2 ExternalValues
 
 This method should return an array reference of hash references.  The
-hash references should contain keys for C<name>, C<description>, and
-C<sortorder>.
+hash references must contain a key for C<name> and can optionally contain
+keys for C<description>, C<sortorder>, and C<category>. If supplying a
+category, you must also set the category the custom field is based on in
+the custom field configuration page.
 
 =head1 SEE ALSO
 
-L<docs/creating_external_custom_fields.pod>
+F<docs/extending/external_custom_fields.pod>
 
 =cut
 
@@ -123,57 +125,49 @@ sub __BuildLimitCheck {
     my ($self, %args) = (@_);
     return undef unless $args{'FIELD'} =~ /^(?:Name|Description)$/;
 
-    $args{'OPERATOR'} ||= '=';
-    my $quoted_value = $args{'VALUE'};
-    if ( $quoted_value ) {
-        $quoted_value =~ s/'/\\'/g;
-        $quoted_value = "'$quoted_value'";
-    }
-
-    my $code = <<END;
-my \$record = shift;
-my \$value = \$record->$args{'FIELD'};
-my \$condition = $quoted_value;
-END
-
-    if ( $args{'OPERATOR'} =~ /^(?:=|!=|<>)$/ ) {
-        $code .= 'return 0 unless defined $value;';
-        my %h = ( '=' => ' eq ', '!=' => ' ne ', '<>' => ' ne ' );
-        $code .= 'return 0 unless $value'. $h{ $args{'OPERATOR'} } .'$condition;';
-        $code .= 'return 1;'
-    }
-    elsif ( $args{'OPERATOR'} =~ /^(?:LIKE|NOT LIKE)$/i ) {
-        $code .= 'return 0 unless defined $value;';
-        my %h = ( 'LIKE' => ' =~ ', 'NOT LIKE' => ' !~ ' );
-        $code .= 'return 0 unless $value'. $h{ uc $args{'OPERATOR'} } .'/\Q$condition/i;';
-        $code .= 'return 1;'
-    }
-    else {
-        $code .= 'return 0;'
-    }
-    $code = "sub {$code}";
-    my $cb = eval "$code";
-    $RT::Logger->error( "Couldn't build callback '$code': $@" ) if $@;
-    return $cb;
+    my $condition = $args{VALUE};
+    my $op = $args{'OPERATOR'} || '=';
+    my $field = $args{FIELD};
+
+    return sub {
+        my $record = shift;
+        my $value = $record->$field;
+        return 0 unless defined $value;
+        if ($op eq "=") {
+            return 0 unless $value eq $condition;
+        } elsif ($op eq "!=" or $op eq "<>") {
+            return 0 unless $value ne $condition;
+        } elsif (uc($op) eq "LIKE") {
+            return 0 unless $value =~ /\Q$condition\E/i;
+        } elsif (uc($op) eq "NOT LIKE") {
+            return 0 unless $value !~ /\Q$condition\E/i;
+        } else {
+            return 0;
+        }
+        return 1;
+    };
 }
 
 sub __BuildAggregatorsCheck {
     my $self = shift;
+    my @cbs = grep {$_->{CALLBACK}} @{ $self->{'__external_cf_limits'} };
+    return undef unless @cbs;
 
-    my %h = ( OR => ' || ', AND => ' && ' );
-    
-    my $code = '';
-    for( my $i = 0; $i < @{ $self->{'__external_cf_limits'} }; $i++ ) {
-        next unless $self->{'__external_cf_limits'}->[$i]->{'CALLBACK'};
-        $code .= $h{ uc($self->{'__external_cf_limits'}->[$i]->{'ENTRYAGGREGATOR'} || 'OR') } if $code;
-        $code .= '$sb->{\'__external_cf_limits\'}->['. $i .']->{\'CALLBACK\'}->($record)';
-    }
-    return unless $code;
+    my %h = (
+        OR  => sub { defined $_[0] ? ($_[0] || $_[1]) : $_[1] },
+        AND => sub { defined $_[0] ? ($_[0] && $_[1]) : $_[1] },
+    );
 
-    $code = "sub { my (\$sb,\$record) = (\@_); return $code }";
-    my $cb = eval "$code";
-    $RT::Logger->error( "Couldn't build callback '$code': $@" ) if $@;
-    return $cb;
+    return sub {
+        my ($sb, $record) = @_;
+        my $ok;
+        for my $limit ( @cbs ) {
+            $ok = $h{$limit->{ENTRYAGGREGATOR} || 'OR'}->(
+                $ok, $limit->{CALLBACK}->($record),
+            );
+        }
+        return $ok;
+    };
 }
 
 sub _DoSearch {
@@ -187,9 +181,10 @@ sub _DoSearch {
             customfield => $self->{'__external_cf'},
             sortorder => 0,
             description => '',
-            creator => $RT::SystemUser->id,
+            category => undef,
+            creator => RT->SystemUser->id,
             created => undef,
-            lastupdatedby => $RT::SystemUser->id,
+            lastupdatedby => RT->SystemUser->id,
             lastupdated => undef,
     );
 
@@ -201,6 +196,7 @@ sub _DoSearch {
         $value->LoadFromHash( { %defaults, %$_ } );
         next if $check && !$check->( $self, $value );
         $self->AddRecord( $value );
+        last if $self->RowsPerPage and ++$i >= $self->RowsPerPage;
     }
     $self->{'must_redo_search'} = 0;
     return $self->_RecordCount;
@@ -222,14 +218,10 @@ sub LimitToCustomField {
     return $self->SUPER::LimitToCustomField( @_ );
 }
 
-eval "require RT::CustomFieldValues::External_Vendor";
-if ($@ && $@ !~ qr{^Can't locate RT/CustomFieldValues/External_Vendor.pm}) {
-    die $@;
-};
+sub _SingularClass {
+    "RT::CustomFieldValue"
+}
 
-eval "require RT::CustomFieldValues::External_Local";
-if ($@ && $@ !~ qr{^Can't locate RT/CustomFieldValues/External_Local.pm}) {
-    die $@;
-};
+RT::Base->_ImportOverlays();
 
 1;