1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC
6 # <jesse@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/copyleft/gpl.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 }}}
50 RT::SearchBuilder - a baseclass for RT collection objects
62 ok (require RT::SearchBuilder);
69 package RT::SearchBuilder;
72 use DBIx::SearchBuilder "1.48";
76 @ISA = qw(DBIx::SearchBuilder RT::Base);
82 $self->{'user'} = shift;
83 unless(defined($self->CurrentUser)) {
85 Carp::confess("$self was created without a CurrentUser");
86 $RT::Logger->err("$self was created without a CurrentUser");
89 $self->SUPER::_Init( 'Handle' => $RT::Handle);
93 # {{{ sub LimitToEnabled
97 Only find items that haven\'t been disabled
104 $self->Limit( FIELD => 'Disabled',
110 # {{{ sub LimitToDisabled
112 =head2 LimitToDeleted
114 Only find items that have been deleted.
121 $self->{'find_disabled_rows'} = 1;
122 $self->Limit( FIELD => 'Disabled',
129 # {{{ sub LimitAttribute
131 =head2 LimitAttribute PARAMHASH
133 Takes NAME, OPERATOR and VALUE to find records that has the
136 If EMPTY is set, also select rows with an empty string as
139 If NULL is set, also select rows without the named Attribute.
157 my ($self, %args) = @_;
158 my $clause = 'ALIAS';
159 my $operator = ($args{OPERATOR} || '=');
161 if ($args{NULL} and exists $args{VALUE}) {
162 $clause = 'LEFTJOIN';
163 $operator = $Negate{$operator};
165 elsif ($args{NEGATE}) {
166 $operator = $Negate{$operator};
169 my $alias = $self->Join(
171 ALIAS1 => $args{ALIAS} || 'main',
173 TABLE2 => 'Attributes',
177 my $type = ref($self);
178 $type =~ s/(?:s|Collection)$//; # XXX - Hack!
182 FIELD => 'ObjectType',
190 VALUE => $args{NAME},
191 ) if exists $args{NAME};
193 return unless exists $args{VALUE};
198 OPERATOR => $operator,
199 VALUE => $args{VALUE},
202 # Capture rows with the attribute defined as an empty string.
208 ENTRYAGGREGATOR => $args{NULL} ? 'AND' : 'OR',
211 # Capture rows without the attribute defined
216 OPERATOR => ($args{NEGATE} ? 'IS NOT' : 'IS'),
222 # {{{ sub LimitCustomField
224 =head2 LimitCustomField
226 Takes a paramhash of key/value pairs with the following keys:
230 =item CUSTOMFIELD - CustomField id. Optional
232 =item OPERATOR - The usual Limit operators
234 =item VALUE - The value to compare against
242 my $class = ref($self);
243 $class =~ s/s$// or die "Cannot deduce SingularClass for $class";
247 sub LimitCustomField {
249 my %args = ( VALUE => undef,
250 CUSTOMFIELD => undef,
254 my $alias = $self->Join(
258 TABLE2 => 'ObjectCustomFieldValues',
263 FIELD => 'CustomField',
265 VALUE => $args{'CUSTOMFIELD'},
266 ) if ($args{'CUSTOMFIELD'});
269 FIELD => 'ObjectType',
271 VALUE => $self->_SingularClass,
276 OPERATOR => $args{'OPERATOR'},
277 VALUE => $args{'VALUE'},
281 # {{{ sub FindAllRows
285 Find all matching rows, regardless of whether they are disabled or not
290 shift->{'find_disabled_rows'} = 1;
295 =head2 Limit PARAMHASH
297 This Limit sub calls SUPER::Limit, but defaults "CASESENSITIVE" to 1, thus
298 making sure that by default lots of things don't do extra work trying to
299 match lower(colname) agaist lc($val);
305 my %args = ( CASESENSITIVE => 1,
308 return $self->SUPER::Limit(%args);
313 # {{{ sub ItemsOrderBy
317 If it has a SortOrder attribute, sort the array by SortOrder.
318 Otherwise, if it has a "Name" attribute, sort alphabetically by Name
319 Otherwise, just give up and return it in the order it came from the
328 if ($self->NewItem()->_Accessible('SortOrder','read')) {
329 $items = [ sort { $a->SortOrder <=> $b->SortOrder } @{$items} ];
331 elsif ($self->NewItem()->_Accessible('Name','read')) {
332 $items = [ sort { lc($a->Name) cmp lc($b->Name) } @{$items} ];
340 # {{{ sub ItemsArrayRef
344 Return this object's ItemsArray, in the order that ItemsOrderBy sorts
350 ok(my $queues = RT::Queues->new($RT::SystemUser), 'Created a queues object');
351 ok( $queues->UnLimit(),'Unlimited the result set of the queues object');
352 my $items = $queues->ItemsArrayRef();
353 my @items = @{$items};
355 ok($queues->NewItem->_Accessible('Name','read'));
356 my @sorted = sort {lc($a->Name) cmp lc($b->Name)} @items;
357 ok (@sorted, "We have an array of queues, sorted". join(',',map {$_->Name} @sorted));
359 ok (@items, "We have an array of queues, raw". join(',',map {$_->Name} @items));
360 my @sorted_ids = map {$_->id } @sorted;
361 my @items_ids = map {$_->id } @items;
363 is ($#sorted, $#items);
364 is ($sorted[0]->Name, $items[0]->Name);
365 is ($sorted[-1]->Name, $items[-1]->Name);
366 is_deeply(\@items_ids, \@sorted_ids, "ItemsArrayRef sorts alphabetically by name");;
377 return $self->ItemsOrderBy($self->SUPER::ItemsArrayRef());
382 eval "require RT::SearchBuilder_Vendor";
383 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SearchBuilder_Vendor.pm});
384 eval "require RT::SearchBuilder_Local";
385 die $@ if ($@ && $@ !~ qr{^Can't locate RT/SearchBuilder_Local.pm});