Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / lib / RT / SearchBuilder / AddAndSort.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
6 #                                          <sales@bestpractical.com>
7 #
8 # (Except where explicitly superseded by other copyright notices)
9 #
10 #
11 # LICENSE:
12 #
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
16 # from www.gnu.org.
17 #
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.
22 #
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.
28 #
29 #
30 # CONTRIBUTION SUBMISSION POLICY:
31 #
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.)
37 #
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.
46 #
47 # END BPS TAGGED BLOCK }}}
48
49 use strict;
50 use warnings;
51
52 package RT::SearchBuilder::AddAndSort;
53 use base 'RT::SearchBuilder';
54
55 =head1 NAME
56
57 RT::SearchBuilder::AddAndSort - base class for 'add and sort' collections
58
59 =head1 DESCRIPTION
60
61 Base class for collections where records can be added to objects with order.
62 See also L<RT::Record::AddAndSort>. Used by L<RT::ObjectScrips> and
63 L<RT::ObjectCustomFields>.
64
65 As it's about sorting then collection is sorted by SortOrder field.
66
67 =head1 METHODS
68
69 =cut
70
71 sub _Init {
72     my $self = shift;
73
74     # By default, order by SortOrder
75     $self->OrderByCols(
76          { ALIAS => 'main',
77            FIELD => 'SortOrder',
78            ORDER => 'ASC' },
79          { ALIAS => 'main',
80            FIELD => 'id',
81            ORDER => 'ASC' },
82     );
83
84     return $self->SUPER::_Init(@_);
85 }
86
87 =head2 LimitToObjectId
88
89 Takes id of an object and limits collection.
90
91 =cut
92
93 sub LimitToObjectId {
94     my $self = shift;
95     my $id = shift || 0;
96     $self->Limit( FIELD => 'ObjectId', VALUE => $id );
97 }
98
99 =head1 METHODS FOR TARGETS
100
101 Rather than implementing a base class for targets (L<RT::Scrip>,
102 L<RT::CustomField>) and its collections. This class provides
103 class methods to limit target collections.
104
105 =head2 LimitTargetToNotAdded
106
107 Takes a collection object and optional list of object ids. Limits the
108 collection to records not added to listed objects or if the list is
109 empty then any object. Use 0 (zero) to mean global.
110
111 =cut
112
113 sub LimitTargetToNotAdded {
114     my $self = shift;
115     my $collection = shift;
116     my @ids = @_;
117
118     my $alias = $self->JoinTargetToAdded($collection => @ids);
119
120     $collection->Limit(
121         ENTRYAGGREGATOR => 'AND',
122         ALIAS    => $alias,
123         FIELD    => 'id',
124         OPERATOR => 'IS',
125         VALUE    => 'NULL',
126     );
127     return $alias;
128 }
129
130 =head2 LimitTargetToAdded
131
132 L</LimitTargetToNotAdded> with reverse meaning. Takes the same
133 arguments.
134
135 =cut
136
137 sub LimitTargetToAdded {
138     my $self = shift;
139     my $collection = shift;
140     my @ids = @_;
141
142     my $alias = $self->JoinTargetToAdded($collection => @ids);
143
144     $collection->Limit(
145         ENTRYAGGREGATOR => 'AND',
146         ALIAS    => $alias,
147         FIELD    => 'id',
148         OPERATOR => 'IS NOT',
149         VALUE    => 'NULL',
150     );
151     return $alias;
152 }
153
154 =head2 JoinTargetToAdded
155
156 Joins collection to this table using left join, limits joined table
157 by ids if those are provided.
158
159 Returns alias of the joined table. Join is cached and re-used for
160 multiple calls.
161
162 =cut
163
164 sub JoinTargetToAdded {
165     my $self = shift;
166     my $collection = shift;
167     my @ids = @_;
168
169     my $alias = $self->JoinTargetToThis( $collection, New => 0, Left => 1 );
170     return $alias unless @ids;
171
172     # XXX: we need different EA in join clause, but DBIx::SB
173     # doesn't support them, use IN (X) instead
174     my $dbh = $self->_Handle->dbh;
175     $collection->Limit(
176         LEFTJOIN   => $alias,
177         ALIAS      => $alias,
178         FIELD      => 'ObjectId',
179         OPERATOR   => 'IN',
180         QUOTEVALUE => 0,
181         VALUE      => "(". join( ',', map $dbh->quote($_), @ids ) .")",
182     );
183
184     return $alias;
185 }
186
187 =head2 JoinTargetToThis
188
189 Joins target collection to this table using TargetField.
190
191 Takes New and Left arguments. Use New to avoid caching and re-using
192 this join. Use Left to create LEFT JOIN rather than inner.
193
194 =cut
195
196 sub JoinTargetToThis {
197     my $self = shift;
198     my $collection = shift;
199     my %args = ( New => 0, Left => 0, @_ );
200
201     my $table = $self->Table;
202     my $key = "_sql_${table}_alias";
203
204     return $collection->{ $key } if $collection->{ $key } && !$args{'New'};
205
206     my $alias = $collection->Join(
207         $args{'Left'} ? (TYPE => 'LEFT') : (),
208         ALIAS1 => 'main',
209         FIELD1 => 'id',
210         TABLE2 => $table,
211         FIELD2 => $self->RecordClass->TargetField,
212     );
213     return $alias if $args{'New'};
214     return $collection->{ $key } = $alias;
215 }
216
217 RT::Base->_ImportOverlays();
218
219 1;