]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/support-scripts/authority_control_fields.pl
Qstore: support LIMIT and OFFSET clauses.
[working/Evergreen.git] / Open-ILS / src / support-scripts / authority_control_fields.pl
1 #!/usr/bin/perl
2 # Copyright (C) 2010 Laurentian University
3 # Author: Dan Scott <dscott@laurentian.ca>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 # ---------------------------------------------------------------
15
16 use strict;
17 use warnings;
18 use DBI;
19 use Getopt::Long;
20 use MARC::Record;
21 use MARC::File::XML;
22 use OpenSRF::System;
23 use OpenILS::Utils::Fieldmapper;
24 use OpenSRF::Utils::SettingsClient;
25 use Encode;
26 use Unicode::Normalize;
27 use OpenILS::Application::AppUtils;
28 # use Data::Dumper;
29
30 =head1
31
32 For a given set of records (specified by ID at the command line, or special option --all):
33
34 =over
35
36 =item * Iterate through the list of fields that are controlled fields
37
38 =item * Iterate through the list of subfields that are controlled for
39 that given field
40
41 =item * Search for a matching authority record for that combination of
42 field + subfield(s)
43
44 =over
45
46 =item * If we find a match, then add a $0 subfield to that field identifying
47 the controlling authority record
48
49 =item * If we do not find a match, then insert a row into an "uncontrolled"
50 table identifying the record ID, field, and subfield(s) that were not controlled
51
52 =back
53
54 =item * Iterate through the list of floating subdivisions
55
56 =over
57
58 =item * If we find a match, then add a $0 subfield to that field identifying
59 the controlling authority record
60
61 =item * If we do not find a match, then insert a row into an "uncontrolled"
62 table identifying the record ID, field, and subfield(s) that were not controlled
63
64 =back
65
66 =item * If we changed the record, update it in the database
67
68 =back
69
70 =cut
71
72 my $all_records;
73 my $bootstrap = '/openils/conf/opensrf_core.xml';
74 my @records;
75 my $result = GetOptions(
76     'configuration=s' => \$bootstrap,
77     'record=s' => \@records,
78     'all' => \$all_records
79 );
80
81 OpenSRF::System->bootstrap_client(config_file => $bootstrap);
82 Fieldmapper->import(IDL => OpenSRF::Utils::SettingsClient->new->config_value("IDL"));
83
84 # must be loaded and initialized after the IDL is parsed
85 use OpenILS::Utils::CStoreEditor;
86 OpenILS::Utils::CStoreEditor::init();
87
88 my $editor = OpenILS::Utils::CStoreEditor->new;
89 if ($all_records) {
90     # get a list of all non-deleted records from Evergreen
91     # open-ils.cstore open-ils.cstore.direct.biblio.record_entry.id_list.atomic {"deleted":"f"}
92     push @records, $editor->request( 
93         'open-ils.cstore.direct.biblio.record_entry.id_list.atomic', 
94         {deleted => 'f'},
95         {id => { '>' => 0}}
96     );
97 }
98 # print Dumper(\@records);
99
100 # Hash of controlled fields & subfields in bibliographic records, and their
101 # corresponding controlling fields & subfields in the authority record
102 #
103 # So, if the bib 650$a can be controlled by an auth 150$a, that maps to:
104 # 650 => { a => { 150 => 'a'}}
105 my %controllees = (
106     110 =>  { a => { 110 => 'a' },
107               d => { 110 => 'd' },
108               e => { 110 => 'e' }
109             },
110     711 =>  { a => { 111 => 'a' },
111               c => { 111 => 'c' },
112               d => { 111 => 'd' }
113             }
114     
115 );
116
117 foreach my $rec_id (@records) {
118
119     my $e = OpenILS::Utils::CStoreEditor->new(xact=>1);
120     # State variable; was the record changed?
121     my $changed;
122
123     # get the record
124     my $record = $e->retrieve_biblio_record_entry($rec_id);
125     next unless $record;
126     # print Dumper($record);
127
128     my $marc = MARC::Record->new_from_xml($record->marc());
129
130     # get the list of controlled fields
131     my @c_fields = keys %controllees;
132
133     foreach my $c_tag (@c_fields) {
134         my @c_subfields = keys %{$controllees{"$c_tag"}};
135         # print "Field: $field subfields: ";
136         # foreach (@subfields) { print "$_ "; }
137
138         # Get the MARCXML from the record and check for controlled fields/subfields
139         my @bib_fields = ($marc->field($c_tag));
140         foreach my $bib_field (@bib_fields) {
141             # print $_->as_formatted(); 
142             my %match_subfields;
143             my $match_tag;
144             my @searches;
145             foreach my $c_subfield (@c_subfields) {
146                 my $sf = $bib_field->subfield($c_subfield);
147                 if ($sf) {
148                     # Give me the first element of the list of authority controlling tags for this subfield
149                     # XXX Will we need to support more than one controlling tag per subfield? Probably. That
150                     # will suck. Oh well, leave that up to Ole to implement.
151                     $match_subfields{$c_subfield} = (keys %{$controllees{$c_tag}{$c_subfield}})[0];
152                     $match_tag = $match_subfields{$c_subfield};
153                     push @searches, {term => $sf, subfield => $c_subfield};
154                 }
155             }
156             # print Dumper(\%match_subfields);
157
158             my @tags = ($match_tag);
159             # Now we've built up a complete set of matching controlled
160             # subfields for this particular field; let's check to see if
161             # we have a matching authority record
162             my $session = OpenSRF::AppSession->create("open-ils.search");
163             my $validates = $session->request("open-ils.search.authority.validate.tag.id_list", 
164                 "tags", \@tags, "searches", \@searches
165             )->gather();
166             $session->disconnect();
167
168             # print Dumper($validates);
169
170             if (scalar(@$validates) == 0) {
171                 next;
172             }
173
174             # Okay, we have a matching authority control; time to
175             # add the magical subfield 0
176             my $auth_id = @$validates[0];
177             my $auth_rec = $e->retrieve_authority_record_entry($auth_id);
178             my $auth_marc = MARC::Record->new_from_xml($auth_rec->marc());
179             my $cni = $auth_marc->field('003')->data();
180             
181             $bib_field->add_subfields('0' => "($cni)$auth_id");
182             $changed = 1;
183         }
184     }
185     if ($changed) {
186         # print $marc->as_formatted();
187         my $xml = $marc->as_xml_record();
188         $xml =~ s/\n//sgo;
189         $xml =~ s/^<\?xml.+\?\s*>//go;
190         $xml =~ s/>\s+</></go;
191         $xml =~ s/\p{Cc}//go;
192         $xml = OpenILS::Application::AppUtils->entityize($xml);
193
194         $record->marc($xml);
195         $e->update_biblio_record_entry($record);
196     }
197     $e->commit();
198 }