-
Notifications
You must be signed in to change notification settings - Fork 257
/
Heading.pm
293 lines (215 loc) · 7.35 KB
/
Heading.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package C4::Heading;
# Copyright (C) 2008 LibLime
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use MARC::Field;
use C4::Context;
use Module::Load qw( load );
use List::Util qw( none );
=head1 NAME
C4::Heading
=head1 SYNOPSIS
use C4::Heading;
my $heading = C4::Heading->new_from_field($field, $frameworkcode);
my $thesaurus = $heading->thesaurus();
my $type = $heading->type();
my $display_heading = $heading->display_form();
my $search_form = $heading->search_form();
=head1 DESCRIPTION
C<C4::Heading> implements a simple class to representing
headings found in bibliographic and authority records.
=head1 METHODS
=head2 new_from_field
my $heading = C4::Heading->new_from_field($field, $frameworkcode, [, $auth]);
Given a C<MARC::Field> object containing a heading from a
bib record, create a C<C4::Heading> object.
The optional third parameter is 'auth' - it is handled as boolean. If supplied we treat the field as an auth record field. Otherwise if it is a bib field. The fields checked are the same in a UNIMARC system and this parameter is ignored
If the MARC field supplied is not a valid heading, undef
is returned.
=cut
sub new_from_field {
my $class = shift;
my $field = shift;
my $frameworkcode = shift; #FIXME this is not used?
my $auth = shift;
my $marcflavour = C4::Context->preference('marcflavour');
my $marc_handler = _marc_format_handler($marcflavour);
return unless $field;
my $tag = $field->tag();
return unless $marc_handler->valid_heading_tag( $tag, $frameworkcode, $auth );
my $self = {};
$self->{'field'} = $field;
(
$self->{'auth_type'}, $self->{'thesaurus'},
$self->{'search_form'}, $self->{'display_form'},
$self->{'match_type'}
) = $marc_handler->parse_heading($field, $auth );
bless $self, $class;
return $self;
}
=head2 auth_type
my $auth_type = $heading->auth_type();
Return the auth_type of the heading.
=cut
sub auth_type {
my $self = shift;
return $self->{'auth_type'};
}
=head2 field
my $field = $heading->field();
Return the MARC::Field the heading is based on.
=cut
sub field {
my $self = shift;
return $self->{'field'};
}
=head2 display_form
my $display = $heading->display_form();
Return the "canonical" display form of the heading.
=cut
sub display_form {
my $self = shift;
return $self->{'display_form'};
}
=head2 search_form
my $search_form = $heading->search_form();
Return the "canonical" search form of the heading.
=cut
sub search_form {
my $self = shift;
return $self->{'search_form'};
}
=head2 authorities
my $authorities = $heading->authorities([$skipmetadata]);
Return a list of authority records for this
heading. If passed a true value for $skipmetadata,
SearchAuthorities will return only authids.
=cut
sub authorities {
my $self = shift;
my $skipmetadata = shift;
my ( $results, $total ) = _search( $self, 'match-heading', $skipmetadata );
return $results;
}
=head2 preferred_authorities
my $preferred_authorities = $heading->preferred_authorities;
Return a list of authority records for headings
that are a preferred form of the heading.
=cut
sub preferred_authorities {
my $self = shift;
my $skipmetadata = shift || undef;
my ( $results, $total ) = _search( 'see-from', $skipmetadata );
return $results;
}
=head2 valid_heading_subfield
if (C4::Heading::valid_heading_subfield('100', 'e', '')) ...
Check if the given subfield is valid for the given field.
=cut
sub valid_heading_subfield {
my $tag = shift;
my $subfield = shift;
my $marcflavour = C4::Context->preference('marcflavour');
my $auth = shift;
my $marc_handler = _marc_format_handler($marcflavour);
return $marc_handler->valid_heading_subfield( $tag, $subfield, $auth );
}
=head1 INTERNAL METHODS
=head2 _search
=cut
sub _search {
my $self = shift;
my $index = shift || undef;
my $skipmetadata = shift || undef;
my $thesaurus = $self->{thesaurus};
my $subject_heading_thesaurus = '';
my @marclist;
my @and_or;
my @excluding = [];
my @operator;
my @value;
my $check_thesaurus = C4::Context->preference('LinkerConsiderThesaurus');
# FIXME: We specify values for @and_or and @excluding
# but these fields are not used anywhere and should be removed
if ($index) {
push @marclist, $index;
push @and_or, 'AND';
push @operator, $self->{'match_type'};
push @value, $self->{'search_form'};
}
if ( $check_thesaurus && $thesaurus ) {
push @marclist, 'thesaurus';
push @and_or, 'and';
push @excluding, '';
push @operator, 'is';
push @value, $thesaurus;
}
require Koha::SearchEngine::QueryBuilder;
require Koha::SearchEngine::Search;
# Use state variables to avoid recreating the objects every time.
# With Elasticsearch this also avoids creating a massive amount of
# ES connectors that would eventually run out of file descriptors.
state $builder = Koha::SearchEngine::QueryBuilder->new(
{ index => $Koha::SearchEngine::AUTHORITIES_INDEX } );
state $searcher = Koha::SearchEngine::Search->new(
{index => $Koha::SearchEngine::AUTHORITIES_INDEX} );
my $search_query = $builder->build_authorities_query_compat(
\@marclist, \@and_or, \@excluding, \@operator,
\@value, $self->{'auth_type'},
'AuthidAsc'
);
my ( $matched_auths, $total ) = $searcher->search_auth_compat( $search_query, 0, 20, $skipmetadata );
# Some auth records may not contain the 040$f to specify their source
# This is legal, so we do a fallback search
if (
$check_thesaurus
&& !$total
&& $thesaurus
&& none { $_ eq $thesaurus } (
'lcsh', 'lcac', 'mesh', 'nal',
'notspecified', 'cash', 'rvm', 'sears',
'aat'
)
)
{
pop @value;
push @value, 'notdefined';
$search_query =
$builder->build_authorities_query_compat( \@marclist, \@and_or,
\@excluding, \@operator, \@value, $self->{'auth_type'},
'AuthidAsc' );
( $matched_auths, $total ) =
$searcher->search_auth_compat( $search_query, 0, 20, $skipmetadata );
}
return ( $matched_auths, $total );
}
=head1 INTERNAL FUNCTIONS
=head2 _marc_format_handler
Returns a C4::Heading::MARC21 or C4::Heading::UNIMARC object
depending on the selected MARC flavour.
=cut
sub _marc_format_handler {
my $marcflavour = uc shift;
my $pname = "C4::Heading::$marcflavour";
load $pname;
return $pname->new();
}
=head1 AUTHOR
Koha Development Team <http://koha-community.org/>
Galen Charlton <[email protected]>
=cut
1;