rt 4.0.23
[freeside.git] / rt / lib / RT / SearchBuilder.pm
index ec4a223..bfc0cd3 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)
@@ -70,6 +70,7 @@ use DBIx::SearchBuilder "1.50";
 use strict;
 use warnings;
 
+
 use base qw(DBIx::SearchBuilder RT::Base);
 
 sub _Init  {
@@ -85,6 +86,44 @@ sub _Init  {
     $self->SUPER::_Init( 'Handle' => $RT::Handle);
 }
 
+sub _Handle { return $RT::Handle }
+
+sub CleanSlate {
+    my $self = shift;
+    $self->{'_sql_aliases'} = {};
+    delete $self->{'handled_disabled_column'};
+    delete $self->{'find_disabled_rows'};
+    return $self->SUPER::CleanSlate(@_);
+}
+
+sub JoinTransactions {
+    my $self = shift;
+    my %args = ( New => 0, @_ );
+
+    return $self->{'_sql_aliases'}{'transactions'}
+        if !$args{'New'} && $self->{'_sql_aliases'}{'transactions'};
+
+    my $alias = $self->Join(
+        ALIAS1 => 'main',
+        FIELD1 => 'id',
+        TABLE2 => 'Transactions',
+        FIELD2 => 'ObjectId',
+    );
+
+    my $item = $self->NewItem;
+    my $object_type = $item->can('ObjectType') ? $item->ObjectType : ref $item;
+
+    $self->RT::SearchBuilder::Limit(
+        LEFTJOIN => $alias,
+        FIELD    => 'ObjectType',
+        VALUE    => $object_type,
+    );
+    $self->{'_sql_aliases'}{'transactions'} = $alias
+        unless $args{'New'};
+
+    return $alias;
+}
+
 sub OrderByCols {
     my $self = shift;
     my @sort;
@@ -96,6 +135,19 @@ sub OrderByCols {
     return $self->SUPER::OrderByCols( @sort );
 }
 
+# If we're setting RowsPerPage or FirstRow, ensure we get a natural number or undef.
+sub RowsPerPage {
+    my $self = shift;
+    return if @_ and defined $_[0] and $_[0] =~ /\D/;
+    return $self->SUPER::RowsPerPage(@_);
+}
+
+sub FirstRow {
+    my $self = shift;
+    return if @_ and defined $_[0] and $_[0] =~ /\D/;
+    return $self->SUPER::FirstRow(@_);
+}
+
 =head2 LimitToEnabled
 
 Only find items that haven't been disabled
@@ -132,96 +184,6 @@ sub FindAllRows {
     shift->{'find_disabled_rows'} = 1;
 }
 
-=head2 LimitAttribute PARAMHASH
-
-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 = (
-    '='        => '!=',
-    '!='       => '=',
-    '>'        => '<=',
-    '<'        => '>=',
-    '>='       => '<',
-    '<='       => '>',
-    '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 => $args{ALIAS} || 'main',
-       FIELD1 => 'id',
-       TABLE2 => 'Attributes',
-       FIELD2 => 'ObjectId'
-    );
-
-    my $type = ref($self);
-    $type =~ s/(?:s|Collection)$//; # XXX - Hack!
-
-    $self->Limit(
-       $clause    => $alias,
-       FIELD      => 'ObjectType',
-       OPERATOR   => '=',
-       VALUE      => $type,
-    );
-    $self->Limit(
-       $clause    => $alias,
-       FIELD      => 'Name',
-       OPERATOR   => '=',
-       VALUE      => $args{NAME},
-    ) if exists $args{NAME};
-
-    return unless exists $args{VALUE};
-
-    $self->Limit(
-       $clause    => $alias,
-       FIELD      => 'Content',
-       OPERATOR   => $operator,
-       VALUE      => $args{VALUE},
-    );
-
-    # 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};
-}
-
 =head2 LimitCustomField
 
 Takes a paramhash of key/value pairs with the following keys:
@@ -253,29 +215,35 @@ sub LimitCustomField {
                  @_ );
 
     my $alias = $self->Join(
-       TYPE       => 'left',
-       ALIAS1     => 'main',
-       FIELD1     => 'id',
-       TABLE2     => 'ObjectCustomFieldValues',
-       FIELD2     => 'ObjectId'
+        TYPE       => 'left',
+        ALIAS1     => 'main',
+        FIELD1     => 'id',
+        TABLE2     => 'ObjectCustomFieldValues',
+        FIELD2     => 'ObjectId'
     );
     $self->Limit(
-       ALIAS      => $alias,
-       FIELD      => 'CustomField',
-       OPERATOR   => '=',
-       VALUE      => $args{'CUSTOMFIELD'},
+        ALIAS      => $alias,
+        FIELD      => 'CustomField',
+        OPERATOR   => '=',
+        VALUE      => $args{'CUSTOMFIELD'},
     ) if ($args{'CUSTOMFIELD'});
     $self->Limit(
-       ALIAS      => $alias,
-       FIELD      => 'ObjectType',
-       OPERATOR   => '=',
-       VALUE      => $self->_SingularClass,
+        ALIAS      => $alias,
+        FIELD      => 'ObjectType',
+        OPERATOR   => '=',
+        VALUE      => $self->_SingularClass,
     );
     $self->Limit(
-       ALIAS      => $alias,
-       FIELD      => 'Content',
-       OPERATOR   => $args{'OPERATOR'},
-       VALUE      => $args{'VALUE'},
+        ALIAS      => $alias,
+        FIELD      => 'Content',
+        OPERATOR   => $args{'OPERATOR'},
+        VALUE      => $args{'VALUE'},
+    );
+    $self->Limit(
+        ALIAS => $alias,
+        FIELD => 'Disabled',
+        OPERATOR => '=',
+        VALUE => 0,
     );
 }
 
@@ -315,7 +283,8 @@ sub Limit {
                                   |(NOT\s*)?(STARTS|ENDS)WITH
                                   |(NOT\s*)?MATCHES
                                   |IS(\s*NOT)?
-                                  |IN)$/ix) {
+                                  |(NOT\s*)?IN
+                                  |\@\@)$/ix) {
         $RT::Logger->crit("Possible SQL injection attack: $ARGS{FIELD} $ARGS{OPERATOR}");
         $self->SUPER::Limit(
             %ARGS,
@@ -389,6 +358,22 @@ sub _DoCount {
     return $self->SUPER::_DoCount(@_);
 }
 
+=head2 ColumnMapClassName
+
+ColumnMap needs a Collection name to load the correct list display.
+Depluralization is hard, so provide an easy way to correct the naive
+algorithm that this code uses.
+
+=cut
+
+sub ColumnMapClassName {
+    my $self = shift;
+    my $Class = ref $self;
+    $Class =~ s/s$//;
+    $Class =~ s/:/_/g;
+    return $Class;
+}
+
 RT::Base->_ImportOverlays();
 
 1;