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