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