Merge remote-tracking branch 'origin/new/bug_7284'
[koha.git] / 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 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 =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;
44
45 use C4::Context;
46 use C4::Charset qw/StripNonXmlChars/;
47 use C4::Biblio;
48 use C4::OAI::Sets;
49
50 my %opts;
51 $Getopt::Std::STANDARD_HELP_VERSION = 1;
52 my $go = getopts('vo:l:ihr', \%opts);
53
54 if(!$go or $opts{h}){
55     &print_usage;
56     exit;
57 }
58
59 my $verbose = $opts{v};
60 my $offset = $opts{o};
61 my $length = $opts{l};
62 my $embed_items = $opts{i};
63 my $reset = $opts{r};
64
65 my $dbh = C4::Context->dbh;
66
67 # Get OAI sets mappings
68 my $mappings = GetOAISetsMappings;
69
70 # Get all biblionumbers and marcxml
71 print "Retrieving biblios... " if $verbose;
72 my $query = qq{
73     SELECT biblionumber, marcxml
74     FROM biblioitems
75 };
76 if($length) {
77     $query .= "LIMIT $length";
78     if($offset) {
79         $query .= " OFFSET $offset";
80     }
81 }
82 my $sth = $dbh->prepare($query);
83 $sth->execute;
84 my $results = $sth->fetchall_arrayref({});
85 print "done.\n" if $verbose;
86
87 # Build lists of parents sets
88 my $sets = GetOAISets;
89 my $parentsets;
90 foreach my $set (@$sets) {
91     my $setSpec = $set->{'spec'};
92     while($setSpec =~ /^(.+):(.+)$/) {
93         my $parent = $1;
94         my $parent_set = GetOAISetBySpec($parent);
95         if($parent_set) {
96             push @{ $parentsets->{$set->{'id'}} }, $parent_set->{'id'};
97             $setSpec = $parent;
98         } else {
99             last;
100         }
101     }
102 }
103
104 my $num_biblios = scalar @$results;
105 my $i = 1;
106 my $sets_biblios = {};
107 foreach my $res (@$results) {
108     my $biblionumber = $res->{'biblionumber'};
109     my $marcxml = $res->{'marcxml'};
110     if($verbose and $i % 1000 == 0) {
111         my $percent = ($i * 100) / $num_biblios;
112         $percent = sprintf("%.2f", $percent);
113         say "Progression: $i/$num_biblios ($percent %)";
114     }
115     # The following lines are copied from GetMarcBiblio
116     # We don't call GetMarcBiblio to avoid a sql query to be executed each time
117     $marcxml = StripNonXmlChars($marcxml);
118     MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
119     my $record;
120     eval {
121         $record = MARC::Record::new_from_xml($marcxml, "utf8", C4::Context->preference('marcflavour'));
122     };
123     if($@) {
124         warn "(biblio $biblionumber) Error while creating record from marcxml: $@";
125         next;
126     }
127     if($embed_items) {
128         C4::Biblio::EmbedItemsInMarcBiblio($record, $biblionumber);
129     }
130
131     my @biblio_sets = CalcOAISetsBiblio($record, $mappings);
132     foreach my $set_id (@biblio_sets) {
133         push @{ $sets_biblios->{$set_id} }, $biblionumber;
134         foreach my $parent_set_id ( @{ $parentsets->{$set_id} } ) {
135             push @{ $sets_biblios->{$parent_set_id} }, $biblionumber;
136         }
137     }
138     $i++;
139 }
140 say "Progression: done." if $verbose;
141
142 say "Summary:";
143 foreach my $set_id (keys %$sets_biblios) {
144     $sets_biblios->{$set_id} = [ uniq @{ $sets_biblios->{$set_id} } ];
145     my $set = GetOAISet($set_id);
146     my $setSpec = $set->{'spec'};
147     say "Set '$setSpec': ". scalar(@{$sets_biblios->{$set_id}}) ." biblios";
148 }
149
150 print "Updating database... ";
151 if($reset) {
152     ModOAISetsBiblios( {} );
153 }
154 AddOAISetsBiblios($sets_biblios);
155 print "done.\n";
156
157 sub print_usage {
158     print "build_oai_sets.pl: Build OAI-PMH sets, according to mappings defined in Koha\n";
159     print "Usage: build_oai_sets.pl [-h] [-v] [-i] [-l LENGTH [-o OFFSET]]\n\n";
160     print "\t-h\t\tPrint this help and exit\n";
161     print "\t-v\t\tBe verbose\n";
162     print "\t-i\t\tEmbed items informations, mandatory if you defined mappings on item fields\n";
163     print "\t-l LENGTH\tProcess LENGTH biblios\n";
164     print "\t-o OFFSET\tIf LENGTH is defined, start processing from OFFSET\n\n";
165 }