File Coverage

File:C4/OAI/Sets.pm
Coverage:6.3%

linestmtbrancondsubtimecode
1package 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
37BEGIN {
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
69sub 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
105sub 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
143sub 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
175sub 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
224sub 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
255sub 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
327sub 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
355sub 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
397sub 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
433sub 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
457sub 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
481sub 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
520sub 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
543sub 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
571sub 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
5891;