RT 4.0.13
[freeside.git] / rt / lib / RT / CustomFields.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 =head1 NAME
50
51   RT::CustomFields - a collection of RT CustomField objects
52
53 =head1 SYNOPSIS
54
55   use RT::CustomFields;
56
57 =head1 DESCRIPTION
58
59 =head1 METHODS
60
61
62
63 =cut
64
65
66 package RT::CustomFields;
67
68 use strict;
69 use warnings;
70
71 use DBIx::SearchBuilder::Unique;
72
73 use RT::CustomField;
74
75 use base 'RT::SearchBuilder';
76
77 sub Table { 'CustomFields'}
78
79 sub _Init {
80     my $self = shift;
81
82   # By default, order by SortOrder
83   $self->OrderByCols(
84          { ALIAS => 'main',
85            FIELD => 'SortOrder',
86            ORDER => 'ASC' },
87          { ALIAS => 'main',
88            FIELD => 'Name',
89            ORDER => 'ASC' },
90          { ALIAS => 'main',
91            FIELD => 'id',
92            ORDER => 'ASC' },
93      );
94     $self->{'with_disabled_column'} = 1;
95
96     return ( $self->SUPER::_Init(@_) );
97 }
98
99
100 =head2 LimitToLookupType
101
102 Takes LookupType and limits collection.
103
104 =cut
105
106 sub LimitToLookupType  {
107     my $self = shift;
108     my $lookup = shift;
109
110     $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" );
111 }
112
113 =head2 LimitToChildType
114
115 Takes partial LookupType and limits collection to records
116 where LookupType is equal or ends with the value.
117
118 =cut
119
120 sub LimitToChildType  {
121     my $self = shift;
122     my $lookup = shift;
123
124     $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" );
125     $self->Limit( FIELD => 'LookupType', ENDSWITH => "$lookup" );
126 }
127
128
129 =head2 LimitToParentType
130
131 Takes partial LookupType and limits collection to records
132 where LookupType is equal or starts with the value.
133
134 =cut
135
136 sub LimitToParentType  {
137     my $self = shift;
138     my $lookup = shift;
139
140     $self->Limit( FIELD => 'LookupType', VALUE => "$lookup" );
141     $self->Limit( FIELD => 'LookupType', STARTSWITH => "$lookup" );
142 }
143
144
145 =head2 LimitToGlobalOrObjectId
146
147 Takes list of object IDs and limits collection to custom
148 fields that are applied to these objects or globally.
149
150 =cut
151
152 sub LimitToGlobalOrObjectId {
153     my $self = shift;
154     my $global_only = 1;
155
156
157     foreach my $id (@_) {
158         $self->Limit( ALIAS           => $self->_OCFAlias,
159                     FIELD           => 'ObjectId',
160                     OPERATOR        => '=',
161                     VALUE           => $id || 0,
162                     ENTRYAGGREGATOR => 'OR' );
163         $global_only = 0 if $id;
164     }
165
166     $self->Limit( ALIAS           => $self->_OCFAlias,
167                  FIELD           => 'ObjectId',
168                  OPERATOR        => '=',
169                  VALUE           => 0,
170                  ENTRYAGGREGATOR => 'OR' ) unless $global_only;
171 }
172
173 sub _LimitToOCFs {
174     my $self = shift;
175     my @ids = @_;
176
177     my $ocfs_alias = $self->_OCFAlias( New => 1, Left => 1 );
178     if ( @ids ) {
179         # XXX: we need different EA in join clause, but DBIx::SB
180         # doesn't support them, use IN (X) instead
181         my $dbh = $self->_Handle->dbh;
182         $self->Limit(
183             LEFTJOIN   => $ocfs_alias,
184             ALIAS      => $ocfs_alias,
185             FIELD      => 'ObjectId',
186             OPERATOR   => 'IN',
187             QUOTEVALUE => 0,
188             VALUE      => "(". join( ',', map $dbh->quote($_), @ids ) .")",
189         );
190     }
191
192     return $ocfs_alias;
193 }
194
195 =head2 LimitToNotApplied
196
197 Takes either list of object ids or nothing. Limits collection
198 to custom fields to listed objects or any corespondingly. Use
199 zero to mean global.
200
201 =cut
202
203 sub LimitToNotApplied {
204     my $self = shift;
205     my @ids = @_;
206
207     my $ocfs_alias = $self->_LimitToOCFs(@ids);
208
209     $self->Limit(
210         ENTRYAGGREGATOR => 'AND',
211         ALIAS    => $ocfs_alias,
212         FIELD    => 'id',
213         OPERATOR => 'IS',
214         VALUE    => 'NULL',
215     );
216 }
217
218 =head2 LimitToApplied
219
220 Limits collection to custom fields to listed objects or any corespondingly. Use
221 zero to mean global.
222
223 =cut
224
225 sub LimitToApplied {
226     my $self = shift;
227     my @ids = @_;
228
229     my $ocfs_alias = $self->_LimitToOCFs(@ids);
230
231     $self->Limit(
232         ENTRYAGGREGATOR => 'AND',
233         ALIAS    => $ocfs_alias,
234         FIELD    => 'id',
235         OPERATOR => 'IS NOT',
236         VALUE    => 'NULL',
237     );
238 }
239
240 =head2 LimitToGlobalOrQueue QUEUEID
241
242 DEPRECATED since CFs are applicable not only to tickets these days.
243
244 Limits the set of custom fields found to global custom fields or those tied to the queue with ID QUEUEID
245
246 =cut
247
248 sub LimitToGlobalOrQueue {
249     my $self = shift;
250     my $queue = shift;
251     $self->LimitToGlobalOrObjectId( $queue );
252     $self->LimitToLookupType( 'RT::Queue-RT::Ticket' );
253 }
254
255
256 =head2 LimitToQueue QUEUEID
257
258 DEPRECATED since CFs are applicable not only to tickets these days.
259
260 Takes a queue id (numerical) as its only argument. Makes sure that
261 Scopes it pulls out apply to this queue (or another that you've selected with
262 another call to this method
263
264 =cut
265
266 sub LimitToQueue  {
267    my $self = shift;
268   my $queue = shift;
269
270   $self->Limit (ALIAS => $self->_OCFAlias,
271                 ENTRYAGGREGATOR => 'OR',
272                 FIELD => 'ObjectId',
273                 VALUE => "$queue")
274       if defined $queue;
275   $self->LimitToLookupType( 'RT::Queue-RT::Ticket' );
276 }
277
278
279 =head2 LimitToGlobal
280
281 DEPRECATED since CFs are applicable not only to tickets these days.
282
283 Makes sure that Scopes it pulls out apply to all queues
284 (or another that you've selected with
285 another call to this method or LimitToQueue)
286
287 =cut
288
289 sub LimitToGlobal  {
290    my $self = shift;
291
292   $self->Limit (ALIAS => $self->_OCFAlias,
293                 ENTRYAGGREGATOR => 'OR',
294                 FIELD => 'ObjectId',
295                 VALUE => 0);
296   $self->LimitToLookupType( 'RT::Queue-RT::Ticket' );
297 }
298
299
300 =head2 ApplySortOrder
301
302 Sort custom fields according to thier order application to objects. It's
303 expected that collection contains only records of one
304 L<RT::CustomField/LookupType> and applied to one object or globally
305 (L</LimitToGlobalOrObjectId>), otherwise sorting makes no sense.
306
307 =cut
308
309 sub ApplySortOrder {
310     my $self = shift;
311     my $order = shift || 'ASC';
312     $self->OrderByCols( {
313         ALIAS => $self->_OCFAlias,
314         FIELD => 'SortOrder',
315         ORDER => $order,
316     } );
317 }
318
319
320 =head2 ContextObject
321
322 Returns context object for this collection of custom fields,
323 but only if it's defined.
324
325 =cut
326
327 sub ContextObject {
328     my $self = shift;
329     return $self->{'context_object'};
330 }
331
332
333 =head2 SetContextObject
334
335 Sets context object for this collection of custom fields.
336
337 =cut
338
339 sub SetContextObject {
340     my $self = shift;
341     return $self->{'context_object'} = shift;
342 }
343
344
345 sub _OCFAlias {
346     my $self = shift;
347     my %args = ( New => 0, Left => 0, @_ );
348
349     return $self->{'_sql_ocfalias'} if $self->{'_sql_ocfalias'} && !$args{'New'};
350
351     my $alias = $self->Join(
352         $args{'Left'} ? (TYPE => 'LEFT') : (),
353         ALIAS1 => 'main',
354         FIELD1 => 'id',
355         TABLE2 => 'ObjectCustomFields',
356         FIELD2 => 'CustomField'
357     );
358     return $alias if $args{'New'};
359     return $self->{'_sql_ocfalias'} = $alias;
360 }
361
362
363 =head2 Next
364
365 Returns the next custom field that this user can see.
366
367 =cut
368
369 sub Next {
370     my $self = shift;
371
372     my $CF = $self->SUPER::Next();
373     return $CF unless $CF;
374
375     $CF->SetContextObject( $self->ContextObject );
376
377     return $self->Next unless $CF->CurrentUserHasRight('SeeCustomField');
378     return $CF;
379 }
380
381 =head2 NewItem
382
383 Returns an empty new RT::CustomField item
384 Overrides <RT::SearchBuilder/NewItem> to make sure </ContextObject>
385 is inherited.
386
387 =cut
388
389 sub NewItem {
390     my $self = shift;
391     my $res = RT::CustomField->new($self->CurrentUser);
392     $res->SetContextObject($self->ContextObject);
393     return $res;
394 }
395
396 RT::Base->_ImportOverlays();
397
398 1;