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