Bug 10855: Squash several fixes
[koha.git] / Koha / AdditionalField.pm
1 package Koha::AdditionalField;
2
3 use Modern::Perl;
4
5 use base qw(Class::Accessor);
6
7 use C4::Context;
8
9 __PACKAGE__->mk_accessors(qw( id tablename name authorised_value_category marcfield searchable values ));
10
11 sub new {
12     my ( $class, $args ) = @_;
13
14     my $additional_field = {
15         id => $args->{id} // q||,
16         tablename => $args->{tablename} // q||,
17         name => $args->{name} // q||,
18         authorised_value_category => $args->{authorised_value_category} // q||,
19         marcfield => $args->{marcfield} // q||,
20         searchable => $args->{searchable} // 0,
21         values => $args->{values} // {},
22     };
23
24     my $self = $class->SUPER::new( $additional_field );
25
26     bless $self, $class;
27     return $self;
28 }
29
30 sub fetch {
31     my ( $self ) = @_;
32     my $dbh = C4::Context->dbh;
33     my $field_id = $self->id;
34     return unless $field_id;
35     my $data = $dbh->selectrow_hashref(
36         q|
37             SELECT id, tablename, name, authorised_value_category, marcfield, searchable
38             FROM additional_fields
39             WHERE id = ?
40         |,
41         {}, ( $field_id )
42     );
43
44     die "This additional field does not exist (id=$field_id)" unless $data;
45     $self->{id} = $data->{id};
46     $self->{tablename} = $data->{tablename};
47     $self->{name} = $data->{name};
48     $self->{authorised_value_category} = $data->{authorised_value_category};
49     $self->{marcfield} = $data->{marcfield};
50     $self->{searchable} = $data->{searchable};
51     return $self;
52 }
53
54 sub update {
55     my ( $self ) = @_;
56
57     die "There is no id defined for this additional field. I cannot update it" unless $self->{id};
58
59     my $dbh = C4::Context->dbh;
60     local $dbh->{RaiseError} = 1;
61
62     return $dbh->do(q|
63         UPDATE additional_fields
64         SET name = ?,
65             authorised_value_category = ?,
66             marcfield = ?,
67             searchable = ?
68         WHERE id = ?
69     |, {}, ( $self->{name}, $self->{authorised_value_category}, $self->{marcfield}, $self->{searchable}, $self->{id} ) );
70 }
71
72 sub delete {
73     my ( $self ) = @_;
74     return unless $self->{id};
75     my $dbh = C4::Context->dbh;
76     local $dbh->{RaiseError} = 1;
77     return $dbh->do(q|
78         DELETE FROM additional_fields WHERE id = ?
79     |, {}, ( $self->{id} ) );
80 }
81
82 sub insert {
83     my ( $self ) = @_;
84     my $dbh = C4::Context->dbh;
85     local $dbh->{RaiseError} = 1;
86     $dbh->do(q|
87         INSERT INTO additional_fields
88         ( tablename, name, authorised_value_category, marcfield, searchable )
89         VALUES ( ?, ?, ?, ?, ? )
90     |, {}, ( $self->{tablename}, $self->{name}, $self->{authorised_value_category}, $self->{marcfield}, $self->{searchable} ) );
91     $self->{id} = $dbh->{mysql_insertid};
92 }
93
94 sub insert_values {
95     my ( $self )  = @_;
96
97     my $dbh = C4::Context->dbh;
98     local $dbh->{RaiseError} = 1;
99     while ( my ( $record_id, $value ) = each %{$self->{values}} ) {
100         next unless defined $value;
101         my $updated = $dbh->do(q|
102             UPDATE additional_field_values
103             SET value = ?
104             WHERE field_id = ?
105             AND record_id = ?
106         |, {}, ( $value, $self->{id}, $record_id ));
107         if ( $updated eq '0E0' ) {
108             $dbh->do(q|
109                 INSERT INTO additional_field_values( field_id, record_id, value )
110                 VALUES( ?, ?, ?)
111             |, {}, ( $self->{id}, $record_id, $value ));
112         }
113     }
114 }
115
116 sub fetch_values {
117     my ( $self, $args ) = @_;
118     my $record_id = $args->{record_id};
119     my $dbh = C4::Context->dbh;
120     my $values = $dbh->selectall_arrayref(
121         q|
122             SELECT *
123             FROM additional_fields af, additional_field_values afv
124             WHERE af.id = afv.field_id
125                 AND af.tablename = ?
126                 AND af.name = ?
127         | . ( $record_id ? q|AND afv.record_id = ?| : '' ),
128         {Slice => {}}, ( $self->{tablename}, $self->{name}, ($record_id ? $record_id : () ) )
129     );
130
131     $self->{values} = {};
132     for my $v ( @$values ) {
133         $self->{values}{$v->{record_id}} = $v->{value};
134     }
135 }
136
137 sub all {
138     my ( $class, $args ) = @_;
139     die "BAD CALL: Don't use fetch_all_values as an instance method"
140         if ref $class and UNIVERSAL::can($class,'can');
141     my $tablename = $args->{tablename};
142     my $searchable = $args->{searchable};
143     my $dbh = C4::Context->dbh;
144     my $query = q|
145         SELECT * FROM additional_fields WHERE 1
146     |;
147     $query .= q| AND tablename = ?|
148         if $tablename;
149
150     $query .= q| AND searchable = ?|
151         if defined $searchable;
152
153     my $results = $dbh->selectall_arrayref(
154         $query, {Slice => {}}, (
155             $tablename ? $tablename : (),
156             defined $searchable ? $searchable : ()
157         )
158     );
159     my @fields;
160     for my $r ( @$results ) {
161         push @fields, Koha::AdditionalField->new({
162             id => $r->{id},
163             tablename => $r->{tablename},
164             name => $r->{name},
165             authorised_value_category => $r->{authorised_value_category},
166             marcfield => $r->{marcfield},
167             searchable => $r->{searchable},
168         });
169     }
170     return \@fields;
171
172 }
173
174 sub fetch_all_values {
175     my ( $class, $args ) = @_;
176     die "BAD CALL: Don't use fetch_all_values as an instance method"
177         if ref $class and UNIVERSAL::can($class,'can');
178
179     my $record_id = $args->{record_id};
180     my $tablename = $args->{tablename};
181     return unless $tablename;
182
183     my $dbh = C4::Context->dbh;
184     my $values = $dbh->selectall_arrayref(
185         q|
186             SELECT afv.record_id, af.name, afv.value
187             FROM additional_fields af, additional_field_values afv
188             WHERE af.id = afv.field_id
189                 AND af.tablename = ?
190         | . ( $record_id ? q| AND afv.record_id = ?| : q|| ),
191         {Slice => {}}, ( $tablename, ($record_id ? $record_id : ()) )
192     );
193
194     my $r;
195     for my $v ( @$values ) {
196         $r->{$v->{record_id}}{$v->{name}} = $v->{value};
197     }
198     return $r;
199 }
200
201 sub get_matching_record_ids {
202     my ( $class, $args ) = @_;
203     die "BAD CALL: Don't use fetch_all_values as an instance method"
204         if ref $class and UNIVERSAL::can($class,'can');
205
206     my $fields = $args->{fields} // [];
207     my $tablename = $args->{tablename};
208     my $exact_match = $args->{exact_match} // 1;
209     return [] unless @$fields;
210
211     my $dbh = C4::Context->dbh;
212     my $query = q|SELECT * FROM |;
213     my ( @subqueries, @args );
214     my $i = 0;
215     for my $field ( @$fields ) {
216         $i++;
217         my $subquery = qq|(
218             SELECT record_id, field$i.name AS field${i}_name
219             FROM additional_field_values afv
220             LEFT JOIN
221                 (
222                     SELECT afv.id, af.name, afv.value
223                     FROM additional_field_values afv, additional_fields af
224                     WHERE afv.field_id = af.id
225                     AND af.name = ?
226                     AND af.tablename = ?
227                     AND value LIKE ?
228                 ) AS field$i USING (id)
229             WHERE field$i.id IS NOT NULL
230         ) AS values$i |;
231         $subquery .= ' USING (record_id)' if $i > 1;
232         push @subqueries, $subquery;
233         push @args, $field->{name}, $tablename, ( $exact_match ? $field->{value} : "%$field->{value}%" );
234     }
235     $query .= join( ' LEFT JOIN ', @subqueries ) . ' WHERE 1';
236     for my $j ( 1 .. $i ) {
237             $query .= qq| AND field${j}_name IS NOT NULL|;
238     }
239     my $values = $dbh->selectall_arrayref( $query, {Slice => {}}, @args );
240     return [
241         map { $_->{record_id} } @$values
242     ]
243 }
244
245 1;
246
247 __END__
248
249 =head1 NAME
250
251 Koha::AdditionalField
252
253 =head1 SYNOPSIS
254
255     use Koha::AdditionalField;
256     my $af1 = Koha::AdditionalField->new({id => $id});
257     my $af2 = Koha::AuthorisedValue->new({
258         tablename => 'my_table',
259         name => 'a_name',
260         authorised_value_category => 'LOST',
261         marcfield => '200$a',
262         searchable => 1,
263     });
264     $av1->delete;
265     $av2->{name} = 'another_name';
266     $av2->update;
267
268 =head1 DESCRIPTION
269
270 Class for managing additional fields into Koha.
271
272 =head1 METHODS
273
274 =head2 new
275
276 Create a new Koha::AdditionalField object. This method can be called using several ways.
277 Either with the id for existing field or with different values for a new one.
278
279 =over 4
280
281 =item B<id>
282
283     The caller just knows the id of the additional field and want to retrieve all values.
284
285 =item B<tablename, name, authorised_value_category, marcfield and searchable>
286
287     The caller wants to create a new additional field.
288
289 =back
290
291 =head2 fetch
292
293 The information will be retrieved from the database.
294
295 =head2 update
296
297 If the AdditionalField object has been modified and the values have to be modified into the database, call this method.
298
299 =head2 delete
300
301 Remove a the record in the database using the id the object.
302
303 =head2 insert
304
305 Insert a new AdditionalField object into the database.
306
307 =head2 insert_values
308
309 Insert new values for a record.
310
311     my $af = Koha::AdditionalField({ id => $id })->fetch;
312     my $af->{values} = {
313         record_id1 => 'my value',
314         record_id2 => 'another value',
315     };
316     $af->insert_values;
317
318 =head2 fetch_values
319
320 Retrieve values from the database for a given record_id.
321 The record_id argument is optional.
322
323     my $af = Koha::AdditionalField({ id => $id })->fetch;
324     my $values = $af->fetch_values({record_id => $record_id});
325
326     $values will be equal to something like:
327     {
328         record_id => {
329             field_name1 => 'value1',
330             field_name2 => 'value2',
331         }
332     }
333
334 =head2 all
335
336 Retrieve all additional fields in the database given some parameters.
337 Parameters are optional.
338 This method returns a list of AdditionalField objects.
339 This is a static method.
340
341     my $fields = Koha::AdditionalField->all;
342     or
343     my $fields = Koha::AdditionalField->all{(tablename => 'my_table'});
344     or
345     my $fields = Koha::AdditionalField->all({searchable => 1});
346
347 =head2 fetch_all_values
348
349 Retrieve all values for a table name.
350 This is a static method.
351
352     my $values = Koha::AdditionalField({ tablename => 'my_table' });
353
354     $values will be equel to something like:
355     {
356         record_id1 => {
357             field_name1 => 'value1',
358             field_name2 => 'value2',
359         },
360         record_id2 => {
361             field_name1 => 'value3',
362             field_name2 => 'value4',
363         }
364
365     }
366
367 =head2 get_matching_record_ids
368
369 Retrieve all record_ids for records matching the field values given in parameter.
370 This method returns a list of ids.
371 This is a static method.
372
373     my $fields = [
374         {
375             name => 'field_name',
376             value => 'field_value',
377         }
378     ];
379     my $ids = Koha::AdditionalField->get_matching_record_ids(
380         {
381             tablename => 'subscription',
382             fields => $fields
383         }
384     );
385
386 =head1 AUTHOR
387
388 Jonathan Druart <jonathan.druart at biblibre.com>
389
390 =head1 COPYRIGHT
391
392 Copyright 2013 BibLibre
393
394 =head1 LICENSE
395
396 This file is part of Koha.
397
398 Koha is free software; you can redistribute it and/or modify it under the
399 terms of the GNU General Public License as published by the Free Software
400 Foundation; either version 3 of the License, or (at your option) any later
401 version.
402
403 Koha is distributed in the hope that it will be useful, but WITHOUT ANY
404 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
405 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
406
407 You should have received a copy of the GNU General Public License along
408 with Koha; if not, see <http://www.gnu.org/licenses>.