File: | C4/OAI/Sets.pm |
Coverage: | 6.3% |
line | stmt | bran | cond | sub | time | code |
---|---|---|---|---|---|---|
1 | package C4::OAI::Sets; | |||||
2 | ||||||
3 | # Copyright 2011 BibLibre | |||||
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 - 30 | =head1 NAME C4::OAI::Sets - OAI Sets management functions =head1 DESCRIPTION C4::OAI::Sets contains functions for managing storage and editing of OAI Sets. OAI Set description can be found L<here|http://www.openarchives.org/OAI/openarchivesprotocol.html#Set> =cut | |||||
31 | ||||||
32 | 19 19 19 | 36784 77340 253 | use Modern::Perl; | |||
33 | 19 19 19 | 1794 90 195 | use C4::Context; | |||
34 | ||||||
35 | 19 19 19 | 116 75 2078 | use vars qw(@ISA @EXPORT); | |||
36 | ||||||
37 | BEGIN { | |||||
38 | 21 | 151 | require Exporter; | |||
39 | 19 | 944 | @ISA = qw(Exporter); | |||
40 | 19 | 43829 | @EXPORT = qw( | |||
41 | &GetOAISets &GetOAISet &GetOAISetBySpec &ModOAISet &DelOAISet &AddOAISet | |||||
42 | &GetOAISetsMappings &GetOAISetMappings &ModOAISetMappings | |||||
43 | &GetOAISetsBiblio &ModOAISetsBiblios &AddOAISetsBiblios | |||||
44 | &CalcOAISetsBiblio &UpdateOAISetsBiblio | |||||
45 | ); | |||||
46 | } | |||||
47 | ||||||
48 - 67 | =head1 FUNCTIONS =head2 GetOAISets $oai_sets = GetOAISets; GetOAISets return a array reference of hash references describing the sets. The hash references looks like this: { 'name' => 'set name', 'spec' => 'set spec', 'descriptions' => [ 'description 1', 'description 2', ... ] } =cut | |||||
68 | ||||||
69 | sub GetOAISets { | |||||
70 | 0 | my $dbh = C4::Context->dbh; | ||||
71 | 0 | my $query = qq{ | ||||
72 | SELECT * FROM oai_sets | |||||
73 | }; | |||||
74 | 0 | my $sth = $dbh->prepare($query); | ||||
75 | 0 | $sth->execute; | ||||
76 | 0 | my $results = $sth->fetchall_arrayref({}); | ||||
77 | ||||||
78 | 0 | $query = qq{ | ||||
79 | SELECT description | |||||
80 | FROM oai_sets_descriptions | |||||
81 | WHERE set_id = ? | |||||
82 | }; | |||||
83 | 0 | $sth = $dbh->prepare($query); | ||||
84 | 0 | foreach my $set (@$results) { | ||||
85 | 0 | $sth->execute($set->{'id'}); | ||||
86 | 0 | my $desc = $sth->fetchall_arrayref({}); | ||||
87 | 0 | foreach (@$desc) { | ||||
88 | 0 0 | push @{$set->{'descriptions'}}, $_->{'description'}; | ||||
89 | } | |||||
90 | } | |||||
91 | ||||||
92 | 0 | return $results; | ||||
93 | } | |||||
94 | ||||||
95 - 103 | =head2 GetOAISet $set = GetOAISet($set_id); GetOAISet returns a hash reference describing the set with the given set_id. See GetOAISets to see what the hash looks like. =cut | |||||
104 | ||||||
105 | sub GetOAISet { | |||||
106 | 0 | my ($set_id) = @_; | ||||
107 | ||||||
108 | 0 | return unless $set_id; | ||||
109 | ||||||
110 | 0 | my $dbh = C4::Context->dbh; | ||||
111 | 0 | my $query = qq{ | ||||
112 | SELECT * | |||||
113 | FROM oai_sets | |||||
114 | WHERE id = ? | |||||
115 | }; | |||||
116 | 0 | my $sth = $dbh->prepare($query); | ||||
117 | 0 | $sth->execute($set_id); | ||||
118 | 0 | my $set = $sth->fetchrow_hashref; | ||||
119 | ||||||
120 | 0 | $query = qq{ | ||||
121 | SELECT description | |||||
122 | FROM oai_sets_descriptions | |||||
123 | WHERE set_id = ? | |||||
124 | }; | |||||
125 | 0 | $sth = $dbh->prepare($query); | ||||
126 | 0 | $sth->execute($set->{'id'}); | ||||
127 | 0 | my $desc = $sth->fetchall_arrayref({}); | ||||
128 | 0 | foreach (@$desc) { | ||||
129 | 0 0 | push @{$set->{'descriptions'}}, $_->{'description'}; | ||||
130 | } | |||||
131 | ||||||
132 | 0 | return $set; | ||||
133 | } | |||||
134 | ||||||
135 - 141 | =head2 GetOAISetBySpec my $set = GetOAISetBySpec($setSpec); Returns a hash describing the set whose spec is $setSpec =cut | |||||
142 | ||||||
143 | sub GetOAISetBySpec { | |||||
144 | 0 | my $setSpec = shift; | ||||
145 | ||||||
146 | 0 | return unless defined $setSpec; | ||||
147 | ||||||
148 | 0 | my $dbh = C4::Context->dbh; | ||||
149 | 0 | my $query = qq{ | ||||
150 | SELECT * | |||||
151 | FROM oai_sets | |||||
152 | WHERE spec = ? | |||||
153 | LIMIT 1 | |||||
154 | }; | |||||
155 | 0 | my $sth = $dbh->prepare($query); | ||||
156 | 0 | $sth->execute($setSpec); | ||||
157 | ||||||
158 | 0 | return $sth->fetchrow_hashref; | ||||
159 | } | |||||
160 | ||||||
161 - 173 | =head2 ModOAISet my $set = { 'id' => $set_id, # mandatory 'spec' => $spec, # mandatory 'name' => $name, # mandatory 'descriptions => \@descriptions, # optional, [] to remove descriptions }; ModOAISet($set); ModOAISet modify a set in the database. =cut | |||||
174 | ||||||
175 | sub ModOAISet { | |||||
176 | 0 | my ($set) = @_; | ||||
177 | ||||||
178 | 0 | return unless($set && $set->{'spec'} && $set->{'name'}); | ||||
179 | ||||||
180 | 0 | if(!defined $set->{'id'}) { | ||||
181 | 0 | warn "Set ID not defined, can't modify the set"; | ||||
182 | 0 | return; | ||||
183 | } | |||||
184 | ||||||
185 | 0 | my $dbh = C4::Context->dbh; | ||||
186 | 0 | my $query = qq{ | ||||
187 | UPDATE oai_sets | |||||
188 | SET spec = ?, | |||||
189 | name = ? | |||||
190 | WHERE id = ? | |||||
191 | }; | |||||
192 | 0 | my $sth = $dbh->prepare($query); | ||||
193 | 0 | $sth->execute($set->{'spec'}, $set->{'name'}, $set->{'id'}); | ||||
194 | ||||||
195 | 0 | if($set->{'descriptions'}) { | ||||
196 | 0 | $query = qq{ | ||||
197 | DELETE FROM oai_sets_descriptions | |||||
198 | WHERE set_id = ? | |||||
199 | }; | |||||
200 | 0 | $sth = $dbh->prepare($query); | ||||
201 | 0 | $sth->execute($set->{'id'}); | ||||
202 | ||||||
203 | 0 0 | if(scalar @{$set->{'descriptions'}} > 0) { | ||||
204 | 0 | $query = qq{ | ||||
205 | INSERT INTO oai_sets_descriptions (set_id, description) | |||||
206 | VALUES (?,?) | |||||
207 | }; | |||||
208 | 0 | $sth = $dbh->prepare($query); | ||||
209 | 0 0 | foreach (@{ $set->{'descriptions'} }) { | ||||
210 | 0 | $sth->execute($set->{'id'}, $_) if $_; | ||||
211 | } | |||||
212 | } | |||||
213 | } | |||||
214 | } | |||||
215 | ||||||
216 - 222 | =head2 DelOAISet DelOAISet($set_id); DelOAISet remove the set with the given set_id =cut | |||||
223 | ||||||
224 | sub DelOAISet { | |||||
225 | 0 | my ($set_id) = @_; | ||||
226 | ||||||
227 | 0 | return unless $set_id; | ||||
228 | ||||||
229 | 0 | my $dbh = C4::Context->dbh; | ||||
230 | 0 | my $query = qq{ | ||||
231 | DELETE oai_sets, oai_sets_descriptions, oai_sets_mappings | |||||
232 | FROM oai_sets | |||||
233 | LEFT JOIN oai_sets_descriptions ON oai_sets_descriptions.set_id = oai_sets.id | |||||
234 | LEFT JOIN oai_sets_mappings ON oai_sets_mappings.set_id = oai_sets.id | |||||
235 | WHERE oai_sets.id = ? | |||||
236 | }; | |||||
237 | 0 | my $sth = $dbh->prepare($query); | ||||
238 | 0 | $sth->execute($set_id); | ||||
239 | } | |||||
240 | ||||||
241 - 253 | =head2 AddOAISet my $set = { 'id' => $set_id, # mandatory 'spec' => $spec, # mandatory 'name' => $name, # mandatory 'descriptions => \@descriptions, # optional }; my $set_id = AddOAISet($set); AddOAISet adds a new set and returns its id, or undef if something went wrong. =cut | |||||
254 | ||||||
255 | sub AddOAISet { | |||||
256 | 0 | my ($set) = @_; | ||||
257 | ||||||
258 | 0 | return unless($set && $set->{'spec'} && $set->{'name'}); | ||||
259 | ||||||
260 | 0 | my $set_id; | ||||
261 | 0 | my $dbh = C4::Context->dbh; | ||||
262 | 0 | my $query = qq{ | ||||
263 | INSERT INTO oai_sets (spec, name) | |||||
264 | VALUES (?,?) | |||||
265 | }; | |||||
266 | 0 | my $sth = $dbh->prepare($query); | ||||
267 | 0 | if( $sth->execute($set->{'spec'}, $set->{'name'}) ) { | ||||
268 | 0 | $set_id = $dbh->last_insert_id(undef, undef, 'oai_sets', undef); | ||||
269 | 0 | if($set->{'descriptions'}) { | ||||
270 | 0 | $query = qq{ | ||||
271 | INSERT INTO oai_sets_descriptions (set_id, description) | |||||
272 | VALUES (?,?) | |||||
273 | }; | |||||
274 | 0 | $sth = $dbh->prepare($query); | ||||
275 | 0 0 | foreach( @{ $set->{'descriptions'} } ) { | ||||
276 | 0 | $sth->execute($set_id, $_) if $_; | ||||
277 | } | |||||
278 | } | |||||
279 | } else { | |||||
280 | 0 | warn "AddOAISet failed"; | ||||
281 | } | |||||
282 | ||||||
283 | 0 | return $set_id; | ||||
284 | } | |||||
285 | ||||||
286 - 325 | =head2 GetOAISetsMappings my $mappings = GetOAISetsMappings; GetOAISetsMappings returns mappings for all OAI Sets. Mappings define how biblios are categorized in sets. A mapping is defined by three properties: { marcfield => 'XXX', # the MARC field to check marcsubfield => 'Y', # the MARC subfield to check marcvalue => 'zzzz', # the value to check } If defined in a set mapping, a biblio which have at least one 'Y' subfield of one 'XXX' field equal to 'zzzz' will belong to this set. If multiple mappings are defined in a set, the biblio will belong to this set if at least one condition is matched. GetOAISetsMappings returns a hashref of arrayrefs of hashrefs. The first hashref keys are the sets IDs, so it looks like this: $mappings = { '1' => [ { marcfield => 'XXX', marcsubfield => 'Y', marcvalue => 'zzzz' }, { ... }, ... ], '2' => [...], ... }; =cut | |||||
326 | ||||||
327 | sub GetOAISetsMappings { | |||||
328 | 0 | my $dbh = C4::Context->dbh; | ||||
329 | 0 | my $query = qq{ | ||||
330 | SELECT * FROM oai_sets_mappings | |||||
331 | }; | |||||
332 | 0 | my $sth = $dbh->prepare($query); | ||||
333 | 0 | $sth->execute; | ||||
334 | ||||||
335 | 0 | my $mappings = {}; | ||||
336 | 0 | while(my $result = $sth->fetchrow_hashref) { | ||||
337 | 0 0 | push @{ $mappings->{$result->{'set_id'}} }, { | ||||
338 | marcfield => $result->{'marcfield'}, | |||||
339 | marcsubfield => $result->{'marcsubfield'}, | |||||
340 | marcvalue => $result->{'marcvalue'} | |||||
341 | }; | |||||
342 | } | |||||
343 | ||||||
344 | 0 | return $mappings; | ||||
345 | } | |||||
346 | ||||||
347 - 353 | =head2 GetOAISetMappings my $set_mappings = GetOAISetMappings($set_id); Return mappings for the set with given set_id. It's an arrayref of hashrefs =cut | |||||
354 | ||||||
355 | sub GetOAISetMappings { | |||||
356 | 0 | my ($set_id) = @_; | ||||
357 | ||||||
358 | 0 | return unless $set_id; | ||||
359 | ||||||
360 | 0 | my $dbh = C4::Context->dbh; | ||||
361 | 0 | my $query = qq{ | ||||
362 | SELECT * | |||||
363 | FROM oai_sets_mappings | |||||
364 | WHERE set_id = ? | |||||
365 | }; | |||||
366 | 0 | my $sth = $dbh->prepare($query); | ||||
367 | 0 | $sth->execute($set_id); | ||||
368 | ||||||
369 | 0 | my @mappings; | ||||
370 | 0 | while(my $result = $sth->fetchrow_hashref) { | ||||
371 | 0 | push @mappings, { | ||||
372 | marcfield => $result->{'marcfield'}, | |||||
373 | marcsubfield => $result->{'marcsubfield'}, | |||||
374 | marcvalue => $result->{'marcvalue'} | |||||
375 | }; | |||||
376 | } | |||||
377 | ||||||
378 | 0 | return \@mappings; | ||||
379 | } | |||||
380 | ||||||
381 - 395 | =head2 ModOAISetMappings { my $mappings = [ { marcfield => 'XXX', marcsubfield => 'Y', marcvalue => 'zzzz' }, ... ]; ModOAISetMappings($set_id, $mappings); ModOAISetMappings modifies mappings of a given set. =cut | |||||
396 | ||||||
397 | sub ModOAISetMappings { | |||||
398 | 0 | my ($set_id, $mappings) = @_; | ||||
399 | ||||||
400 | 0 | return unless $set_id; | ||||
401 | ||||||
402 | 0 | my $dbh = C4::Context->dbh; | ||||
403 | 0 | my $query = qq{ | ||||
404 | DELETE FROM oai_sets_mappings | |||||
405 | WHERE set_id = ? | |||||
406 | }; | |||||
407 | 0 | my $sth = $dbh->prepare($query); | ||||
408 | 0 | $sth->execute($set_id); | ||||
409 | ||||||
410 | 0 | if(scalar @$mappings > 0) { | ||||
411 | 0 | $query = qq{ | ||||
412 | INSERT INTO oai_sets_mappings (set_id, marcfield, marcsubfield, marcvalue) | |||||
413 | VALUES (?,?,?,?) | |||||
414 | }; | |||||
415 | 0 | $sth = $dbh->prepare($query); | ||||
416 | 0 | foreach (@$mappings) { | ||||
417 | 0 | $sth->execute($set_id, $_->{'marcfield'}, $_->{'marcsubfield'}, $_->{'marcvalue'}); | ||||
418 | } | |||||
419 | } | |||||
420 | } | |||||
421 | ||||||
422 - 431 | =head2 GetOAISetsBiblio $oai_sets = GetOAISetsBiblio($biblionumber); Return the OAI sets where biblio appears. Return value is an arrayref of hashref where each element of the array is a set. Keys of hash are id, spec and name =cut | |||||
432 | ||||||
433 | sub GetOAISetsBiblio { | |||||
434 | 0 | my ($biblionumber) = @_; | ||||
435 | ||||||
436 | 0 | my $dbh = C4::Context->dbh; | ||||
437 | 0 | my $query = qq{ | ||||
438 | SELECT oai_sets.* | |||||
439 | FROM oai_sets | |||||
440 | LEFT JOIN oai_sets_biblios ON oai_sets_biblios.set_id = oai_sets.id | |||||
441 | WHERE biblionumber = ? | |||||
442 | }; | |||||
443 | 0 | my $sth = $dbh->prepare($query); | ||||
444 | ||||||
445 | 0 | $sth->execute($biblionumber); | ||||
446 | 0 | return $sth->fetchall_arrayref({}); | ||||
447 | } | |||||
448 | ||||||
449 - 455 | =head2 DelOAISetsBiblio DelOAISetsBiblio($biblionumber); Remove a biblio from all sets =cut | |||||
456 | ||||||
457 | sub DelOAISetsBiblio { | |||||
458 | 0 | my ($biblionumber) = @_; | ||||
459 | ||||||
460 | 0 | return unless $biblionumber; | ||||
461 | ||||||
462 | 0 | my $dbh = C4::Context->dbh; | ||||
463 | 0 | my $query = qq{ | ||||
464 | DELETE FROM oai_sets_biblios | |||||
465 | WHERE biblionumber = ? | |||||
466 | }; | |||||
467 | 0 | my $sth = $dbh->prepare($query); | ||||
468 | 0 | return $sth->execute($biblionumber); | ||||
469 | } | |||||
470 | ||||||
471 - 479 | =head2 CalcOAISetsBiblio my @sets = CalcOAISetsBiblio($record, $oai_sets_mappings); Return a list of set ids the record belongs to. $record must be a MARC::Record and $oai_sets_mappings (optional) must be a hashref returned by GetOAISetsMappings =cut | |||||
480 | ||||||
481 | sub CalcOAISetsBiblio { | |||||
482 | 0 | my ($record, $oai_sets_mappings) = @_; | ||||
483 | ||||||
484 | 0 | return unless $record; | ||||
485 | ||||||
486 | 0 | $oai_sets_mappings ||= GetOAISetsMappings; | ||||
487 | ||||||
488 | 0 | my @biblio_sets; | ||||
489 | 0 | foreach my $set_id (keys %$oai_sets_mappings) { | ||||
490 | 0 0 | foreach my $mapping (@{ $oai_sets_mappings->{$set_id} }) { | ||||
491 | 0 | next if not $mapping; | ||||
492 | 0 | my $field = $mapping->{'marcfield'}; | ||||
493 | 0 | my $subfield = $mapping->{'marcsubfield'}; | ||||
494 | 0 | my $value = $mapping->{'marcvalue'}; | ||||
495 | ||||||
496 | 0 | my @subfield_values = $record->subfield($field, $subfield); | ||||
497 | 0 | if(0 < grep /^$value$/, @subfield_values) { | ||||
498 | 0 | push @biblio_sets, $set_id; | ||||
499 | 0 | last; | ||||
500 | } | |||||
501 | } | |||||
502 | } | |||||
503 | 0 | return @biblio_sets; | ||||
504 | } | |||||
505 | ||||||
506 - 518 | =head2 ModOAISetsBiblios my $oai_sets_biblios = { '1' => [1, 3, 4], # key is the set_id, and value is an array ref of biblionumbers '2' => [], ... }; ModOAISetsBiblios($oai_sets_biblios); ModOAISetsBiblios truncate oai_sets_biblios table and call AddOAISetsBiblios. This table is then used in opac/oai.pl. =cut | |||||
519 | ||||||
520 | sub ModOAISetsBiblios { | |||||
521 | 0 | my $oai_sets_biblios = shift; | ||||
522 | ||||||
523 | 0 | return unless ref($oai_sets_biblios) eq "HASH"; | ||||
524 | ||||||
525 | 0 | my $dbh = C4::Context->dbh; | ||||
526 | 0 | my $query = qq{ | ||||
527 | TRUNCATE TABLE oai_sets_biblios | |||||
528 | }; | |||||
529 | 0 | my $sth = $dbh->prepare($query); | ||||
530 | 0 | $sth->execute; | ||||
531 | 0 | AddOAISetsBiblios($oai_sets_biblios); | ||||
532 | } | |||||
533 | ||||||
534 - 541 | =head2 UpdateOAISetsBiblio UpdateOAISetsBiblio($biblionumber, $record); Update OAI sets for one biblio. The two parameters are mandatory. $record is a MARC::Record. =cut | |||||
542 | ||||||
543 | sub UpdateOAISetsBiblio { | |||||
544 | 0 | my ($biblionumber, $record) = @_; | ||||
545 | ||||||
546 | 0 | return unless($biblionumber and $record); | ||||
547 | ||||||
548 | 0 | my $sets_biblios; | ||||
549 | 0 | my @sets = CalcOAISetsBiblio($record); | ||||
550 | 0 | foreach (@sets) { | ||||
551 | 0 0 | push @{ $sets_biblios->{$_} }, $biblionumber; | ||||
552 | } | |||||
553 | 0 | DelOAISetsBiblio($biblionumber); | ||||
554 | 0 | AddOAISetsBiblios($sets_biblios); | ||||
555 | } | |||||
556 | ||||||
557 - 569 | =head2 AddOAISetsBiblios my $oai_sets_biblios = { '1' => [1, 3, 4], # key is the set_id, and value is an array ref of biblionumbers '2' => [], ... }; ModOAISetsBiblios($oai_sets_biblios); AddOAISetsBiblios insert given infos in oai_sets_biblios table. This table is then used in opac/oai.pl. =cut | |||||
570 | ||||||
571 | sub AddOAISetsBiblios { | |||||
572 | 0 | my $oai_sets_biblios = shift; | ||||
573 | ||||||
574 | 0 | return unless ref($oai_sets_biblios) eq "HASH"; | ||||
575 | ||||||
576 | 0 | my $dbh = C4::Context->dbh; | ||||
577 | 0 | my $query = qq{ | ||||
578 | INSERT INTO oai_sets_biblios (set_id, biblionumber) | |||||
579 | VALUES (?,?) | |||||
580 | }; | |||||
581 | 0 | my $sth = $dbh->prepare($query); | ||||
582 | 0 | foreach my $set_id (keys %$oai_sets_biblios) { | ||||
583 | 0 0 | foreach my $biblionumber (@{$oai_sets_biblios->{$set_id}}) { | ||||
584 | 0 | $sth->execute($set_id, $biblionumber); | ||||
585 | } | |||||
586 | } | |||||
587 | } | |||||
588 | ||||||
589 | 1; |