import rt 3.6.4
[freeside.git] / rt / lib / RT / SearchBuilder.pm
index 615f197..178b66b 100644 (file)
@@ -1,8 +1,8 @@
-# {{{ BEGIN BPS TAGGED BLOCK
+# BEGIN BPS TAGGED BLOCK {{{
 # 
 # COPYRIGHT:
 #  
-# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC 
 #                                          <jesse@bestpractical.com>
 # 
 # (Except where explicitly superseded by other copyright notices)
@@ -22,7 +22,9 @@
 # 
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/copyleft/gpl.html.
 # 
 # 
 # CONTRIBUTION SUBMISSION POLICY:
@@ -42,7 +44,7 @@
 # works based on those contributions, and sublicense and distribute
 # those contributions and any derivatives thereof.
 # 
-# }}} END BPS TAGGED BLOCK
+# END BPS TAGGED BLOCK }}}
 =head1 NAME
 
   RT::SearchBuilder - a baseclass for RT collection objects
@@ -67,7 +69,7 @@ ok (require RT::SearchBuilder);
 package RT::SearchBuilder;
 
 use RT::Base;
-use DBIx::SearchBuilder;
+use DBIx::SearchBuilder "1.40";
 
 use strict;
 use vars qw(@ISA);
@@ -131,14 +133,42 @@ sub LimitToDeleted {
 Takes NAME, OPERATOR and VALUE to find records that has the
 matching Attribute.
 
+If EMPTY is set, also select rows with an empty string as
+Attribute's Content.
+
+If NULL is set, also select rows without the named Attribute.
+
 =cut
 
+my %Negate = qw(
+    =          !=
+    !=         =
+    >          <=
+    <          >=
+    >=         <
+    <=         >
+    LIKE       NOT LIKE
+    NOT LIKE   LIKE
+    IS         IS NOT
+    IS NOT     IS
+);
+
 sub LimitAttribute {
     my ($self, %args) = @_;
+    my $clause = 'ALIAS';
+    my $operator = ($args{OPERATOR} || '=');
+    
+    if ($args{NULL} and exists $args{VALUE}) {
+       $clause = 'LEFTJOIN';
+       $operator = $Negate{$operator};
+    }
+    elsif ($args{NEGATE}) {
+       $operator = $Negate{$operator};
+    }
     
     my $alias = $self->Join(
        TYPE   => 'left',
-       ALIAS1 => 'main',
+       ALIAS1 => $args{ALIAS} || 'main',
        FIELD1 => 'id',
        TABLE2 => 'Attributes',
        FIELD2 => 'ObjectId'
@@ -148,13 +178,13 @@ sub LimitAttribute {
     $type =~ s/(?:s|Collection)$//; # XXX - Hack!
 
     $self->Limit(
-       ALIAS      => $alias,
+       $clause    => $alias,
        FIELD      => 'ObjectType',
        OPERATOR   => '=',
        VALUE      => $type,
     );
     $self->Limit(
-       ALIAS      => $alias,
+       $clause    => $alias,
        FIELD      => 'Name',
        OPERATOR   => '=',
        VALUE      => $args{NAME},
@@ -163,27 +193,90 @@ sub LimitAttribute {
     return unless exists $args{VALUE};
 
     $self->Limit(
-       ALIAS      => $alias,
+       $clause    => $alias,
        FIELD      => 'Content',
-       OPERATOR   => ($args{OPERATOR} || '='),
+       OPERATOR   => $operator,
        VALUE      => $args{VALUE},
-       ENTRYAGGREGATOR => 'OR',
     );
 
-    if ($args{EMPTY}) {
-       # Capture rows without the attribute defined by testing IS NULL.
-       $self->Limit(
-           ALIAS      => $alias,
-           FIELD      => $_,
-           OPERATOR   => 'IS',
-           VALUE      => 'NULL',
-           ENTRYAGGREGATOR => 'OR',
-       ) for qw( ObjectType Name Content );
-    }
+    # Capture rows with the attribute defined as an empty string.
+    $self->Limit(
+       $clause    => $alias,
+       FIELD      => 'Content',
+       OPERATOR   => '=',
+       VALUE      => '',
+       ENTRYAGGREGATOR => $args{NULL} ? 'AND' : 'OR',
+    ) if $args{EMPTY};
+
+    # Capture rows without the attribute defined
+    $self->Limit(
+       %args,
+       ALIAS      => $alias,
+       FIELD      => 'id',
+       OPERATOR   => ($args{NEGATE} ? 'IS NOT' : 'IS'),
+       VALUE      => 'NULL',
+    ) if $args{NULL};
 }
 # }}}
 
-1;
+# {{{ sub LimitCustomField
+
+=head2 LimitCustomField
+
+Takes a paramhash of key/value pairs with the following keys:
+
+=over 4
+
+=item CUSTOMFIELD - CustomField id. Optional
+
+=item OPERATOR - The usual Limit operators
+
+=item VALUE - The value to compare against
+
+=back
+
+=cut
+
+sub _SingularClass {
+    my $self = shift;
+    my $class = ref($self);
+    $class =~ s/s$// or die "Cannot deduce SingularClass for $class";
+    return $class;
+}
+
+sub LimitCustomField {
+    my $self = shift;
+    my %args = ( VALUE        => undef,
+                 CUSTOMFIELD  => undef,
+                 OPERATOR     => '=',
+                 @_ );
+
+    my $alias = $self->Join(
+       TYPE       => 'left',
+       ALIAS1     => 'main',
+       FIELD1     => 'id',
+       TABLE2     => 'ObjectCustomFieldValues',
+       FIELD2     => 'ObjectId'
+    );
+    $self->Limit(
+       ALIAS      => $alias,
+       FIELD      => 'CustomField',
+       OPERATOR   => '=',
+       VALUE      => $args{'CUSTOMFIELD'},
+    ) if ($args{'CUSTOMFIELD'});
+    $self->Limit(
+       ALIAS      => $alias,
+       FIELD      => 'ObjectType',
+       OPERATOR   => '=',
+       VALUE      => $self->_SingularClass,
+    );
+    $self->Limit(
+       ALIAS      => $alias,
+       FIELD      => 'Content',
+       OPERATOR   => $args{'OPERATOR'},
+       VALUE      => $args{'VALUE'},
+    );
+}
 
 # {{{ sub FindAllRows
 
@@ -219,7 +312,7 @@ sub Limit {
 
 # {{{ sub ItemsOrderBy
 
-=item ItemsOrderBy
+=head2 ItemsOrderBy
 
 If it has a SortOrder attribute, sort the array by SortOrder.
 Otherwise, if it has a "Name" attribute, sort alphabetically by Name
@@ -246,7 +339,7 @@ sub ItemsOrderBy {
 
 # {{{ sub ItemsArrayRef
 
-=item ItemsArrayRef
+=head2 ItemsArrayRef
 
 Return this object's ItemsArray, in the order that ItemsOrderBy sorts
 it.