1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2016 Best Practical Solutions, LLC
6 # <sales@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 # General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
30 # CONTRIBUTION SUBMISSION POLICY:
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
47 # END BPS TAGGED BLOCK }}}
49 package RT::CustomFieldValues::External;
54 use base qw(RT::CustomFieldValues);
58 RT::CustomFieldValues::External - Pull possible values for a custom
59 field from an arbitrary external data source.
63 Custom field value lists can be produced by creating a class that
64 inherits from C<RT::CustomFieldValues::External>, and overloading
65 C<SourceDescription> and C<ExternalValues>. See
66 L<RT::CustomFieldValues::Groups> for a simple example.
70 Subclasses should implement the following methods:
72 =head2 SourceDescription
74 This method should return a string describing the data source; this is
75 the identifier by which the user will see the dropdown.
79 This method should return an array reference of hash references. The
80 hash references must contain a key for C<name> and can optionally contain
81 keys for C<description>, C<sortorder>, and C<category>. If supplying a
82 category, you must also set the category the custom field is based on in
83 the custom field configuration page.
87 F<docs/extending/external_custom_fields.pod>
94 return ( $self->SUPER::_Init(@_) );
99 delete $self->{ $_ } foreach qw(
103 return $self->SUPER::CleanSlate(@_);
106 sub _ClonedAttributes {
111 ), $self->SUPER::_ClonedAttributes;
117 push @{ $self->{'__external_cf_limits'} ||= [] }, {
119 CALLBACK => $self->__BuildLimitCheck( %args ),
121 return $self->SUPER::Limit( %args );
124 sub __BuildLimitCheck {
125 my ($self, %args) = (@_);
126 return undef unless $args{'FIELD'} =~ /^(?:Name|Description)$/;
128 my $condition = $args{VALUE};
129 my $op = $args{'OPERATOR'} || '=';
130 my $field = $args{FIELD};
134 my $value = $record->$field;
135 return 0 unless defined $value;
137 return 0 unless $value eq $condition;
138 } elsif ($op eq "!=" or $op eq "<>") {
139 return 0 unless $value ne $condition;
140 } elsif (uc($op) eq "LIKE") {
141 return 0 unless $value =~ /\Q$condition\E/i;
142 } elsif (uc($op) eq "NOT LIKE") {
143 return 0 unless $value !~ /\Q$condition\E/i;
151 sub __BuildAggregatorsCheck {
153 my @cbs = grep {$_->{CALLBACK}} @{ $self->{'__external_cf_limits'} };
154 return undef unless @cbs;
157 OR => sub { defined $_[0] ? ($_[0] || $_[1]) : $_[1] },
158 AND => sub { defined $_[0] ? ($_[0] && $_[1]) : $_[1] },
162 my ($sb, $record) = @_;
164 for my $limit ( @cbs ) {
165 $ok = $h{$limit->{ENTRYAGGREGATOR} || 'OR'}->(
166 $ok, $limit->{CALLBACK}->($record),
176 delete $self->{'items'};
181 customfield => $self->{'__external_cf'},
185 creator => RT->SystemUser->id,
187 lastupdatedby => RT->SystemUser->id,
188 lastupdated => undef,
193 my $check = $self->__BuildAggregatorsCheck;
194 foreach( @{ $self->ExternalValues } ) {
195 my $value = $self->NewItem;
196 $value->LoadFromHash( { %defaults, %$_ } );
197 next if $check && !$check->( $self, $value );
198 $self->AddRecord( $value );
199 last if $self->RowsPerPage and ++$i >= $self->RowsPerPage;
201 $self->{'must_redo_search'} = 0;
202 return $self->_RecordCount;
209 $count = $self->_DoSearch if $self->{'must_redo_search'};
210 $count = $self->_RecordCount unless defined $count;
212 return $self->{'count_all'} = $self->{'raw_rows'} = $count;
215 sub LimitToCustomField {
217 $self->{'__external_cf'} = $_[0];
218 return $self->SUPER::LimitToCustomField( @_ );
222 "RT::CustomFieldValue"
225 RT::Base->_ImportOverlays();