Bug 17600: Standardize our EXPORT_OK
[srvgit] / misc / migration_tools / build_oai_sets.pl
1 #!/usr/bin/perl
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
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 =head1 DESCRIPTION
21
22 This script build OAI-PMH sets (to be used by opac/oai.pl) according to sets
23 and mappings defined in Koha. It reads informations from oai_sets and
24 oai_sets_mappings, and then fill table oai_sets_biblios with builded infos.
25
26 =head1 USAGE
27
28     build_oai_sets.pl [-h] [-v] [-r] [-i] [-l LENGTH [-o OFFSET]]
29         -h          Print help message;
30         -v          Be verbose
31         -r          Truncate table oai_sets_biblios before inserting new rows
32         -i          Embed items informations, mandatory if you defined mappings
33                     on item fields
34         -l LENGTH   Process LENGTH biblios
35         -o OFFSET   If LENGTH is defined, start processing from OFFSET
36
37 =cut
38
39 use Modern::Perl;
40 use MARC::Record;
41 use MARC::File::XML;
42 use List::MoreUtils qw( uniq );
43 use Getopt::Std qw( getopts );
44
45 use Koha::Script;
46 use C4::Context;
47 use C4::Charset qw( StripNonXmlChars );
48 use C4::Biblio;
49 use C4::OAI::Sets qw(
50     AddOAISetsBiblios
51     CalcOAISetsBiblio
52     GetOAISet
53     GetOAISetBySpec
54     GetOAISets
55     GetOAISetsMappings
56     ModOAISetsBiblios
57 );
58
59 my %opts;
60 $Getopt::Std::STANDARD_HELP_VERSION = 1;
61 my $go = getopts('vo:l:ihr', \%opts);
62
63 if(!$go or $opts{h}){
64     &print_usage;
65     exit;
66 }
67
68 my $verbose = $opts{v};
69 my $offset = $opts{o};
70 my $length = $opts{l};
71 my $embed_items = $opts{i};
72 my $reset = $opts{r};
73
74 my $dbh = C4::Context->dbh;
75
76 # Get OAI sets mappings
77 my $mappings = GetOAISetsMappings;
78
79 # Get all biblionumbers and marcxml
80 print "Retrieving biblios... " if $verbose;
81 my $query = qq{
82     SELECT biblionumber, metadata
83     FROM biblio_metadata
84     WHERE format='marcxml'
85     AND  `schema` = ?
86     UNION
87     SELECT biblionumber, metadata
88     FROM deletedbiblio_metadata
89     WHERE format='marcxml'
90     AND  `schema` = ?
91 };
92 if($length) {
93     $query .= "LIMIT $length";
94     if($offset) {
95         $query .= " OFFSET $offset";
96     }
97 }
98 my $sth = $dbh->prepare($query);
99 $sth->execute( C4::Context->preference('marcflavour'), C4::Context->preference('marcflavour'));
100 my $results = $sth->fetchall_arrayref({});
101 print "done.\n" if $verbose;
102
103 # Build lists of parents sets
104 my $sets = GetOAISets;
105 my $parentsets;
106 foreach my $set (@$sets) {
107     my $setSpec = $set->{'spec'};
108     while($setSpec =~ /^(.+):(.+)$/) {
109         my $parent = $1;
110         my $parent_set = GetOAISetBySpec($parent);
111         if($parent_set) {
112             push @{ $parentsets->{$set->{'id'}} }, $parent_set->{'id'};
113             $setSpec = $parent;
114         } else {
115             last;
116         }
117     }
118 }
119
120 my $num_biblios = scalar @$results;
121 my $i = 1;
122 my $sets_biblios = {};
123 foreach my $res (@$results) {
124     my $biblionumber = $res->{'biblionumber'};
125     my $marcxml = $res->{'metadata'};
126     if($verbose and $i % 1000 == 0) {
127         my $percent = ($i * 100) / $num_biblios;
128         $percent = sprintf("%.2f", $percent);
129         say "Progression: $i/$num_biblios ($percent %)";
130     }
131     # The following lines are copied from GetMarcBiblio
132     # We don't call GetMarcBiblio to avoid a sql query to be executed each time
133     $marcxml = StripNonXmlChars($marcxml);
134     MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
135     my $record;
136     eval {
137         $record = MARC::Record::new_from_xml($marcxml, "UTF-8", C4::Context->preference('marcflavour'));
138     };
139     if($@) {
140         warn "(biblio $biblionumber) Error while creating record from marcxml: $@";
141         next;
142     }
143     if($embed_items) {
144         C4::Biblio::EmbedItemsInMarcBiblio({
145             marc_record  => $record,
146             biblionumber => $biblionumber });
147     }
148
149     my @biblio_sets = CalcOAISetsBiblio($record, $mappings);
150     foreach my $set_id (@biblio_sets) {
151         push @{ $sets_biblios->{$set_id} }, $biblionumber;
152         foreach my $parent_set_id ( @{ $parentsets->{$set_id} } ) {
153             push @{ $sets_biblios->{$parent_set_id} }, $biblionumber;
154         }
155     }
156     $i++;
157 }
158 say "Progression: done." if $verbose;
159
160 say "Summary:";
161 foreach my $set_id (keys %$sets_biblios) {
162     $sets_biblios->{$set_id} = [ uniq @{ $sets_biblios->{$set_id} } ];
163     my $set = GetOAISet($set_id);
164     my $setSpec = $set->{'spec'};
165     say "Set '$setSpec': ". scalar(@{$sets_biblios->{$set_id}}) ." biblios";
166 }
167
168 print "Updating database... ";
169 if($reset) {
170     ModOAISetsBiblios( {} );
171 }
172 AddOAISetsBiblios($sets_biblios);
173 print "done.\n";
174
175 sub print_usage {
176     print "build_oai_sets.pl: Build OAI-PMH sets, according to mappings defined in Koha\n";
177     print "Usage: build_oai_sets.pl [-h] [-v] [-i] [-l LENGTH [-o OFFSET]]\n\n";
178     print "\t-h\t\tPrint this help and exit\n";
179     print "\t-v\t\tBe verbose\n";
180     print "\t-i\t\tEmbed items informations, mandatory if you defined mappings on item fields\n";
181     print "\t-l LENGTH\tProcess LENGTH biblios\n";
182     print "\t-o OFFSET\tIf LENGTH is defined, start processing from OFFSET\n\n";
183 }