Bug 17825: (followup) Remove unused function AttributeTypeExists
[koha.git] / C4 / Members / AttributeTypes.pm
1 package C4::Members::AttributeTypes;
2
3 # Copyright (C) 2008 LibLime
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use strict;
21 #use warnings; FIXME - Bug 2505
22 use C4::Context;
23
24
25
26 =head1 NAME
27
28 C4::Members::AttributeTypes - mananage extended patron attribute types
29
30 =head1 SYNOPSIS
31
32   my @attribute_types = C4::Members::AttributeTypes::GetAttributeTypes();
33
34   my $attr_type = C4::Members::AttributeTypes->new($code, $description);
35   $attr_type->code($code);
36   $attr_type->description($description);
37   $attr_type->repeatable($repeatable);
38   $attr_type->unique_id($unique_id);
39   $attr_type->opac_display($opac_display);
40   $attr_type->opac_editable($opac_editable);
41   $attr_type->staff_searchable($staff_searchable);
42   $attr_type->authorised_value_category($authorised_value_category);
43   $attr_type->store();
44   $attr_type->delete();
45
46   my $attr_type = C4::Members::AttributeTypes->fetch($code);
47   $attr_type = C4::Members::AttributeTypes->delete($code);
48
49 =head1 FUNCTIONS
50
51 =head2 GetAttributeTypes
52
53   my @attribute_types = C4::Members::AttributeTypes::GetAttributeTypes($all_fields);
54
55 Returns an array of hashrefs of each attribute type defined
56 in the database.  The array is sorted by code.  Each hashref contains
57 at least the following fields:
58
59  - code
60  - description
61
62 If $all_fields is true, then each hashref also contains the other fields from borrower_attribute_types.
63
64 =cut
65
66 sub GetAttributeTypes {
67     my $all    = @_   ? shift : 0;
68     my $no_branch_limit = @_ ? shift : 0;
69     my $branch_limit = $no_branch_limit
70         ? 0
71         : C4::Context->userenv ? C4::Context->userenv->{"branch"} : 0;
72     my $select = $all ? '*'   : 'DISTINCT(code), description, class';
73
74     my $dbh = C4::Context->dbh;
75     my $query = "SELECT $select FROM borrower_attribute_types";
76     $query .= qq{
77         LEFT JOIN borrower_attribute_types_branches ON bat_code = code
78         WHERE b_branchcode = ? OR b_branchcode IS NULL
79     } if $branch_limit;
80     $query .= " ORDER BY code";
81     my $sth    = $dbh->prepare($query);
82     $sth->execute( $branch_limit ? $branch_limit : () );
83     my $results = $sth->fetchall_arrayref({});
84     $sth->finish;
85     return @$results;
86 }
87
88 sub GetAttributeTypes_hashref {
89     my %hash = map {$_->{code} => $_} GetAttributeTypes(@_);
90     return \%hash;
91 }
92
93 =head1 METHODS 
94
95   my $attr_type = C4::Members::AttributeTypes->new($code, $description);
96
97 Create a new attribute type.
98
99 =cut 
100
101 sub new {
102     my $class = shift;
103     my $self = {};
104
105     $self->{'code'} = shift;
106     $self->{'description'} = shift;
107     $self->{'repeatable'} = 0;
108     $self->{'unique_id'} = 0;
109     $self->{'opac_display'} = 0;
110     $self->{'opac_editable'} = 0;
111     $self->{'staff_searchable'} = 0;
112     $self->{'display_checkout'} = 0;
113     $self->{'authorised_value_category'} = '';
114     $self->{'category_code'} = '';
115     $self->{'category_description'} = '';
116     $self->{'class'} = '';
117
118     bless $self, $class;
119     return $self;
120 }
121
122 =head2 fetch
123
124   my $attr_type = C4::Members::AttributeTypes->fetch($code);
125
126 Fetches an attribute type from the database.  If no
127 type with the given C<$code> exists, returns undef.
128
129 =cut
130
131 sub fetch {
132     my $class = shift;
133     my $code = shift;
134     my $self = {};
135     my $dbh = C4::Context->dbh();
136
137     my $sth = $dbh->prepare_cached("
138         SELECT borrower_attribute_types.*, categories.description AS category_description
139         FROM borrower_attribute_types
140         LEFT JOIN categories ON borrower_attribute_types.category_code=categories.categorycode
141         WHERE code =?");
142     $sth->execute($code);
143     my $row = $sth->fetchrow_hashref;
144     $sth->finish();
145     return unless defined $row;
146
147     $self->{'code'}                      = $row->{'code'};
148     $self->{'description'}               = $row->{'description'};
149     $self->{'repeatable'}                = $row->{'repeatable'};
150     $self->{'unique_id'}                 = $row->{'unique_id'};
151     $self->{'opac_display'}              = $row->{'opac_display'};
152     $self->{'opac_editable'}             = $row->{'opac_editable'};
153     $self->{'staff_searchable'}          = $row->{'staff_searchable'};
154     $self->{'display_checkout'}          = $row->{'display_checkout'};
155     $self->{'authorised_value_category'} = $row->{'authorised_value_category'};
156     $self->{'category_code'}             = $row->{'category_code'};
157     $self->{'category_description'}      = $row->{'category_description'};
158     $self->{'class'}                     = $row->{'class'};
159
160     $sth = $dbh->prepare("SELECT branchcode, branchname FROM borrower_attribute_types_branches, branches WHERE b_branchcode = branchcode AND bat_code = ?;");
161     $sth->execute( $code );
162     while ( my $data = $sth->fetchrow_hashref ) {
163         push @{ $self->{branches} }, $data;
164     }
165     $sth->finish();
166
167     bless $self, $class;
168     return $self;
169 }
170
171 =head2 store
172
173   $attr_type->store();
174
175 Stores attribute type in the database.  If the type
176 previously retrieved from the database via the fetch()
177 method, the DB representation of the type is replaced.
178
179 =cut
180
181 sub store {
182     my $self = shift;
183
184     my $dbh = C4::Context->dbh;
185     my $sth;
186     my $existing = __PACKAGE__->fetch($self->{'code'});
187     if (defined $existing) {
188         $sth = $dbh->prepare_cached("UPDATE borrower_attribute_types
189                                      SET description = ?,
190                                          repeatable = ?,
191                                          unique_id = ?,
192                                          opac_display = ?,
193                                          opac_editable = ?,
194                                          staff_searchable = ?,
195                                          authorised_value_category = ?,
196                                          display_checkout = ?,
197                                          category_code = ?,
198                                          class = ?
199                                      WHERE code = ?");
200     } else {
201         $sth = $dbh->prepare_cached("INSERT INTO borrower_attribute_types 
202                                         ( description,
203                                           repeatable,
204                                           unique_id,
205                                           opac_display,
206                                           opac_editable,
207                                           staff_searchable,
208                                           authorised_value_category,
209                                           display_checkout,
210                                           category_code,
211                                           class,
212                                           code
213                                         )
214                                         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
215     }
216
217     $sth->execute(
218         $self->{'description'},
219         $self->{'repeatable'},
220         $self->{'unique_id'},
221         $self->{'opac_display'},
222         $self->{'opac_editable'},
223         $self->{'staff_searchable'} || 0,
224         $self->{'authorised_value_category'},
225         $self->{'display_checkout'},
226         $self->{'category_code'} || undef,
227         $self->{'class'},
228         $self->{'code'}
229     );
230
231     if ( defined $$self{branches} ) {
232         $sth = $dbh->prepare("DELETE FROM borrower_attribute_types_branches WHERE bat_code = ?");
233         $sth->execute( $$self{code} );
234         $sth = $dbh->prepare(
235             "INSERT INTO borrower_attribute_types_branches
236                         ( bat_code, b_branchcode )
237                         VALUES ( ?, ? )"
238         );
239         for my $branchcode ( @{$$self{branches}} ) {
240             next if not $branchcode;
241             $sth->bind_param( 1, $$self{code} );
242             $sth->bind_param( 2, $branchcode );
243             $sth->execute;
244         }
245     }
246     $sth->finish;
247 }
248
249 =head2 code
250
251   my $code = $attr_type->code();
252   $attr_type->code($code);
253
254 Accessor.  Note that the code is immutable once
255 a type is created or fetched from the database.
256
257 =cut
258
259 sub code {
260     my $self = shift;
261     return $self->{'code'};
262 }
263
264 =head2 description
265
266   my $description = $attr_type->description();
267   $attr_type->description($description);
268
269 Accessor.
270
271 =cut
272
273 sub description {
274     my $self = shift;
275     @_ ? $self->{'description'} = shift : $self->{'description'};
276 }
277
278 =head2 branches
279
280 my $branches = $attr_type->branches();
281 $attr_type->branches($branches);
282
283 Accessor.
284
285 =cut
286
287 sub branches {
288     my $self = shift;
289     @_ ? $self->{branches} = shift : $self->{branches};
290 }
291
292 =head2 repeatable
293
294   my $repeatable = $attr_type->repeatable();
295   $attr_type->repeatable($repeatable);
296
297 Accessor.  The C<$repeatable> argument
298 is interpreted as a Perl boolean.
299
300 =cut
301
302 sub repeatable {
303     my $self = shift;
304     @_ ? $self->{'repeatable'} = ((shift) ? 1 : 0) : $self->{'repeatable'};
305 }
306
307 =head2 unique_id
308
309   my $unique_id = $attr_type->unique_id();
310   $attr_type->unique_id($unique_id);
311
312 Accessor.  The C<$unique_id> argument
313 is interpreted as a Perl boolean.
314
315 =cut
316
317 sub unique_id {
318     my $self = shift;
319     @_ ? $self->{'unique_id'} = ((shift) ? 1 : 0) : $self->{'unique_id'};
320 }
321
322 =head2 opac_display
323
324   my $opac_display = $attr_type->opac_display();
325   $attr_type->opac_display($opac_display);
326
327 Accessor.  The C<$opac_display> argument
328 is interpreted as a Perl boolean.
329
330 =cut
331
332 sub opac_display {
333     my $self = shift;
334     @_ ? $self->{'opac_display'} = ((shift) ? 1 : 0) : $self->{'opac_display'};
335 }
336
337 =head2 opac_editable
338
339   my $opac_editable = $attr_type->opac_editable();
340   $attr_type->opac_editable($opac_editable);
341
342 Accessor.  The C<$opac_editable> argument
343 is interpreted as a Perl boolean.
344
345 =cut
346
347 sub opac_editable {
348     my $self = shift;
349     @_ ? $self->{'opac_editable'} = ((shift) ? 1 : 0) : $self->{'opac_editable'};
350 }
351
352 =head2 staff_searchable
353
354   my $staff_searchable = $attr_type->staff_searchable();
355   $attr_type->staff_searchable($staff_searchable);
356
357 Accessor.  The C<$staff_searchable> argument
358 is interpreted as a Perl boolean.
359
360 =cut
361
362 sub staff_searchable {
363     my $self = shift;
364     @_ ? $self->{'staff_searchable'} = ((shift) ? 1 : 0) : $self->{'staff_searchable'};
365 }
366
367 =head2 display_checkout
368
369 my $display_checkout = $attr_type->display_checkout();
370 $attr_type->display_checkout($display_checkout);
371
372 Accessor.  The C<$display_checkout> argument
373 is interpreted as a Perl boolean.
374
375 =cut
376
377 sub display_checkout {
378     my $self = shift;
379     @_ ? $self->{'display_checkout'} = ((shift) ? 1 : 0) : $self->{'display_checkout'};
380 }
381
382 =head2 authorised_value_category
383
384   my $authorised_value_category = $attr_type->authorised_value_category();
385   $attr_type->authorised_value_category($authorised_value_category);
386
387 Accessor.
388
389 =cut
390
391 sub authorised_value_category {
392     my $self = shift;
393     @_ ? $self->{'authorised_value_category'} = shift : $self->{'authorised_value_category'};
394 }
395
396 =head2 category_code
397
398 my $category_code = $attr_type->category_code();
399 $attr_type->category_code($category_code);
400
401 Accessor.
402
403 =cut
404
405 sub category_code {
406     my $self = shift;
407     @_ ? $self->{'category_code'} = shift : $self->{'category_code'};
408 }
409
410 =head2 category_description
411
412 my $category_description = $attr_type->category_description();
413 $attr_type->category_description($category_description);
414
415 Accessor.
416
417 =cut
418
419 sub category_description {
420     my $self = shift;
421     @_ ? $self->{'category_description'} = shift : $self->{'category_description'};
422 }
423
424 =head2 class
425
426 my $class = $attr_type->class();
427 $attr_type->class($class);
428
429 Accessor.
430
431 =cut
432
433 sub class {
434     my $self = shift;
435     @_ ? $self->{'class'} = shift : $self->{'class'};
436 }
437
438
439 =head2 delete
440
441   $attr_type->delete();
442   C4::Members::AttributeTypes->delete($code);
443
444 Delete an attribute type from the database.  The attribute
445 type may be specified either by an object or by a code.
446
447 =cut
448
449 sub delete {
450     my $arg = shift;
451     my $code;
452     if (ref($arg) eq __PACKAGE__) {
453         $code = $arg->{'code'};
454     } else {
455         $code = shift;
456     }
457
458     my $dbh = C4::Context->dbh;
459     my $sth = $dbh->prepare_cached("DELETE FROM borrower_attribute_types WHERE code = ?");
460     $sth->execute($code);
461     $sth->finish;
462 }
463
464 =head2 num_patrons
465
466   my $count = $attr_type->num_patrons();
467
468 Returns the number of patron records that use
469 this attribute type.
470
471 =cut
472
473 sub num_patrons {
474     my $self = shift;
475
476     my $dbh = C4::Context->dbh;
477     my $sth = $dbh->prepare_cached("SELECT COUNT(DISTINCT borrowernumber)
478                                     FROM borrower_attributes
479                                     WHERE code = ?");
480     $sth->execute($self->{code});
481     my ($count) = $sth->fetchrow_array;
482     $sth->finish;
483     return $count;
484 }
485
486 =head2 get_patrons
487
488   my @borrowernumbers = $attr_type->get_patrons($attribute);
489
490 Returns the borrowernumber of the patron records that
491 have an attribute with the specifie value.
492
493 =cut
494
495 sub get_patrons {
496     my $self = shift;
497     my $value = shift;
498
499     my $dbh = C4::Context->dbh;
500     my $sth = $dbh->prepare_cached("SELECT DISTINCT borrowernumber
501                                     FROM borrower_attributes
502                                     WHERE code = ?
503                                     AND   attribute = ?");
504     $sth->execute($self->{code}, $value);
505     my @results;
506     while (my ($borrowernumber) = $sth->fetchrow_array) {
507         push @results, $borrowernumber;
508     } 
509     return @results;
510 }
511
512 =head1 AUTHOR
513
514 Koha Development Team <http://koha-community.org/>
515
516 Galen Charlton <galen.charlton@liblime.com>
517
518 =cut
519
520 1;