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