View | Details | Raw Unified | Return to bug 21958
Collapse All | Expand All

(-)a/C4/AuthoritiesMarc.pm (-57 / +64 lines)
Lines 1-6 Link Here
1
package C4::AuthoritiesMarc;
1
package C4::AuthoritiesMarc;
2
2
3
# Copyright 2000-2002 Katipo Communications
3
# Copyright 2000-2002 Katipo Communications
4
# Copyright 2018 The National Library of Finland, University of Helsinki
4
#
5
#
5
# This file is part of Koha.
6
# This file is part of Koha.
6
#
7
#
Lines 338-347 sub GuessAuthTypeCode { Link Here
338
        '110'=>{authtypecode=>'CORPO_NAME'},
339
        '110'=>{authtypecode=>'CORPO_NAME'},
339
        '111'=>{authtypecode=>'MEETI_NAME'},
340
        '111'=>{authtypecode=>'MEETI_NAME'},
340
        '130'=>{authtypecode=>'UNIF_TITLE'},
341
        '130'=>{authtypecode=>'UNIF_TITLE'},
342
        '147'=>{authtypecode=>'NAME_EVENT'},
341
        '148'=>{authtypecode=>'CHRON_TERM'},
343
        '148'=>{authtypecode=>'CHRON_TERM'},
342
        '150'=>{authtypecode=>'TOPIC_TERM'},
344
        '150'=>{authtypecode=>'TOPIC_TERM'},
343
        '151'=>{authtypecode=>'GEOGR_NAME'},
345
        '151'=>{authtypecode=>'GEOGR_NAME'},
344
        '155'=>{authtypecode=>'GENRE/FORM'},
346
        '155'=>{authtypecode=>'GENRE/FORM'},
347
        '162'=>{authtypecode=>'MED_PERFRM'},
345
        '180'=>{authtypecode=>'GEN_SUBDIV'},
348
        '180'=>{authtypecode=>'GEN_SUBDIV'},
346
        '181'=>{authtypecode=>'GEO_SUBDIV'},
349
        '181'=>{authtypecode=>'GEO_SUBDIV'},
347
        '182'=>{authtypecode=>'CHRON_SUBD'},
350
        '182'=>{authtypecode=>'CHRON_SUBD'},
Lines 920-925 sub BuildSummary { Link Here
920
# construct MARC21 summary
923
# construct MARC21 summary
921
# FIXME - looping over 1XX is questionable
924
# FIXME - looping over 1XX is questionable
922
# since MARC21 authority should have only one 1XX
925
# since MARC21 authority should have only one 1XX
926
        use C4::Heading::MARC21;
927
        my $handler = C4::Heading::MARC21->new();
923
        my $subfields_to_report;
928
        my $subfields_to_report;
924
        foreach my $field ($record->field('1..')) {
929
        foreach my $field ($record->field('1..')) {
925
            my $tag = $field->tag();
930
            my $tag = $field->tag();
Lines 927-957 sub BuildSummary { Link Here
927
# FIXME - 152 is not a good tag to use
932
# FIXME - 152 is not a good tag to use
928
# in MARC21 -- purely local tags really ought to be
933
# in MARC21 -- purely local tags really ought to be
929
# 9XX
934
# 9XX
930
            if ($tag eq '100') {
935
931
                $subfields_to_report = 'abcdefghjklmnopqrstvxyz';
936
            $subfields_to_report = $handler->get_auth_heading_subfields_to_report($tag);
932
            } elsif ($tag eq '110') {
937
933
                $subfields_to_report = 'abcdefghklmnoprstvxyz';
934
            } elsif ($tag eq '111') {
935
                $subfields_to_report = 'acdefghklnpqstvxyz';
936
            } elsif ($tag eq '130') {
937
                $subfields_to_report = 'adfghklmnoprstvxyz';
938
            } elsif ($tag eq '148') {
939
                $subfields_to_report = 'abvxyz';
940
            } elsif ($tag eq '150') {
941
                $subfields_to_report = 'abvxyz';
942
            } elsif ($tag eq '151') {
943
                $subfields_to_report = 'avxyz';
944
            } elsif ($tag eq '155') {
945
                $subfields_to_report = 'abvxyz';
946
            } elsif ($tag eq '180') {
947
                $subfields_to_report = 'vxyz';
948
            } elsif ($tag eq '181') {
949
                $subfields_to_report = 'vxyz';
950
            } elsif ($tag eq '182') {
951
                $subfields_to_report = 'vxyz';
952
            } elsif ($tag eq '185') {
953
                $subfields_to_report = 'vxyz';
954
            }
955
            if ($subfields_to_report) {
938
            if ($subfields_to_report) {
956
                push @authorized, {
939
                push @authorized, {
957
                    heading => $field->as_string($subfields_to_report),
940
                    heading => $field->as_string($subfields_to_report),
Lines 1075-1118 sub GetAuthorizedHeading { Link Here
1075
            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
1058
            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
1076
        }
1059
        }
1077
    } else {
1060
    } else {
1061
        use C4::Heading::MARC21;
1062
        my $handler = C4::Heading::MARC21->new();
1063
1078
        foreach my $field ($record->field('1..')) {
1064
        foreach my $field ($record->field('1..')) {
1079
            my $tag = $field->tag();
1065
            my $subfields = $handler->get_valid_bib_heading_subfields($field->tag());
1080
            next if "152" eq $tag;
1066
            return $field->as_string($subfields) if ($subfields);
1081
# FIXME - 152 is not a good tag to use
1082
# in MARC21 -- purely local tags really ought to be
1083
# 9XX
1084
            if ($tag eq '100') {
1085
                return $field->as_string('abcdefghjklmnopqrstvxyz68');
1086
            } elsif ($tag eq '110') {
1087
                return $field->as_string('abcdefghklmnoprstvxyz68');
1088
            } elsif ($tag eq '111') {
1089
                return $field->as_string('acdefghklnpqstvxyz68');
1090
            } elsif ($tag eq '130') {
1091
                return $field->as_string('adfghklmnoprstvxyz68');
1092
            } elsif ($tag eq '148') {
1093
                return $field->as_string('abvxyz68');
1094
            } elsif ($tag eq '150') {
1095
                return $field->as_string('abvxyz68');
1096
            } elsif ($tag eq '151') {
1097
                return $field->as_string('avxyz68');
1098
            } elsif ($tag eq '155') {
1099
                return $field->as_string('abvxyz68');
1100
            } elsif ($tag eq '180') {
1101
                return $field->as_string('vxyz68');
1102
            } elsif ($tag eq '181') {
1103
                return $field->as_string('vxyz68');
1104
            } elsif ($tag eq '182') {
1105
                return $field->as_string('vxyz68');
1106
            } elsif ($tag eq '185') {
1107
                return $field->as_string('vxyz68');
1108
            } else {
1109
                return $field->as_string();
1110
            }
1111
        }
1067
        }
1112
    }
1068
    }
1113
    return;
1069
    return;
1114
}
1070
}
1115
1071
1072
=head2 CompareFieldWithAuthority
1073
1074
  $match = &CompareFieldWithAuthority({ field => $field, authid => $authid })
1075
1076
Takes a MARC::Field from a bibliographic record and an authid, and returns true if they match.
1077
1078
=cut
1079
1080
sub CompareFieldWithAuthority {
1081
    my $args = shift;
1082
1083
    my $record = GetAuthority($args->{authid});
1084
    return unless (ref $record eq 'MARC::Record');
1085
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
1086
        # UNIMARC has same subfields for bibs and authorities
1087
        foreach my $field ($record->field('2..')) {
1088
            return compare_fields($field, $args->{field}, 'abcdefghijlmnopqrstuvwxyz');
1089
        }
1090
    } else {
1091
        use C4::Heading::MARC21;
1092
        my $handler = C4::Heading::MARC21->new();
1093
1094
        foreach my $field ($record->field('1..')) {
1095
            my $subfields = $handler->get_valid_bib_heading_subfields($field->tag());
1096
            return compare_fields($field, $args->{field}, $subfields) if ($subfields);
1097
        }
1098
    }
1099
    return 0;
1100
}
1101
1116
=head2 BuildAuthHierarchies
1102
=head2 BuildAuthHierarchies
1117
1103
1118
  $text= &BuildAuthHierarchies( $authid, $force)
1104
  $text= &BuildAuthHierarchies( $authid, $force)
Lines 1574-1579 sub get_auth_type_location { Link Here
1574
    }
1560
    }
1575
}
1561
}
1576
1562
1563
=head2 compare_fields
1564
1565
  my match = compare_fields($field1, $field2, 'abcde');
1566
1567
Compares the listed subfields of both fields and return true if they all match
1568
1569
=cut
1570
1571
sub compare_fields {
1572
    my ($field1, $field2, $subfields) = @_;
1573
1574
    foreach my $subfield (split(//, $subfields)) {
1575
        my $subfield1 = $field1->subfield($subfield) // '';
1576
        my $subfield2 = $field2->subfield($subfield) // '';
1577
        return 0 unless $subfield1 eq $subfield2;
1578
    }
1579
    return 1;
1580
}
1581
1582
1577
END { }       # module clean-up code here (global destructor)
1583
END { }       # module clean-up code here (global destructor)
1578
1584
1579
1;
1585
1;
Lines 1584-1589 __END__ Link Here
1584
Koha Development Team <http://koha-community.org/>
1590
Koha Development Team <http://koha-community.org/>
1585
1591
1586
Paul POULAIN paul.poulain@free.fr
1592
Paul POULAIN paul.poulain@free.fr
1593
Ere Maijala ere.maijala@helsinki.fi
1587
1594
1588
=cut
1595
=cut
1589
1596
(-)a/C4/Biblio.pm (-3 / +1 lines)
Lines 701-709 sub _check_valid_auth_link { Link Here
701
    my ( $authid, $field ) = @_;
701
    my ( $authid, $field ) = @_;
702
    require C4::AuthoritiesMarc;
702
    require C4::AuthoritiesMarc;
703
703
704
    my $authorized_heading =
704
    return C4::AuthoritiesMarc::CompareFieldWithAuthority( { 'field' => $field, 'authid' => $authid } );
705
      C4::AuthoritiesMarc::GetAuthorizedHeading( { 'authid' => $authid } ) || '';
706
   return ($field->as_string('abcdefghijklmnopqrstuvwxyz') eq $authorized_heading);
707
}
705
}
708
706
709
=head2 GetBiblioData
707
=head2 GetBiblioData
(-)a/C4/Heading.pm (+2 lines)
Lines 172-177 sub preferred_authorities { Link Here
172
172
173
    if (C4::Heading::valid_heading_subfield('100', 'e', '')) ...
173
    if (C4::Heading::valid_heading_subfield('100', 'e', '')) ...
174
174
175
Check if the given subfield is valid for the given field.
176
175
=cut
177
=cut
176
178
177
sub valid_heading_subfield {
179
sub valid_heading_subfield {
(-)a/C4/Heading/MARC21.pm (-13 / +109 lines)
Lines 68-73 my $bib_heading_fields = { Link Here
68
        subfields  => 'adfghklmnoprst',
68
        subfields  => 'adfghklmnoprst',
69
        main_entry => 1
69
        main_entry => 1
70
    },
70
    },
71
    '147' => {
72
        auth_type => 'NAME_EVENT',
73
        subfields => 'acdgvxyz68',
74
        main_entry => 1
75
    },
76
    '148' => {
77
        auth_type => 'CHRON_TERM',
78
        subfields => 'abvxyz68',
79
        main_entry => 1
80
    },
81
    '150' => {
82
        auth_type => 'TOPIC_TERM',
83
        subfields => 'abvxyz68',
84
        main_entry => 1
85
    },
86
    '151' => {
87
        auth_type => 'GEOGR_NAME',
88
        subfields => 'avxyz68',
89
        main_entry => 1
90
    },
91
    '155' => {
92
        auth_type => 'GENRE/FORM',
93
        subfields => 'abvxyz68',
94
        main_entry => 1
95
    },
96
    '162' => {
97
        auth_type => 'MED_PERFRM',
98
        subfields => 'a68',
99
        main_entry => 1
100
    },
101
    '180' => {
102
        auth_type => 'TOPIC_TERM',
103
        subfields => 'vxyz68'
104
    },
105
    '181' => {
106
        auth_type => 'GEOGR_NAME',
107
        subfields => 'vxyz68'
108
    },
109
    '182' => {
110
        auth_type => 'CHRON_TERM',
111
        subfields => 'vxyz68'
112
    },
113
    '185' => {
114
        auth_type => 'GENRE/FORM',
115
        subfields => 'vxyz68'
116
    },
71
    '440' => { auth_type => 'UNIF_TITLE', subfields => 'anp', series => 1 },
117
    '440' => { auth_type => 'UNIF_TITLE', subfields => 'anp', series => 1 },
72
    '600' => {
118
    '600' => {
73
        auth_type => 'PERSO_NAME',
119
        auth_type => 'PERSO_NAME',
Lines 122-165 my $bib_heading_fields = { Link Here
122
my $auth_heading_fields = {
168
my $auth_heading_fields = {
123
    '100' => {
169
    '100' => {
124
        auth_type  => 'PERSO_NAME',
170
        auth_type  => 'PERSO_NAME',
125
        subfields  => 'abcdfghjklmnopqrstvxyz',
171
        subfields  => 'abcdefghjklmnopqrstvxyz68',
126
        main_entry => 1
172
        main_entry => 1
127
    },
173
    },
128
    '110' => {
174
    '110' => {
129
        auth_type  => 'CORPO_NAME',
175
        auth_type  => 'CORPO_NAME',
130
        subfields  => 'abcdfghklmnoprstvxyz',
176
        subfields  => 'abcdefghklmnoprstvxyz68',
131
        main_entry => 1
177
        main_entry => 1
132
    },
178
    },
133
    '111' => {
179
    '111' => {
134
        auth_type  => 'MEETI_NAME',
180
        auth_type  => 'MEETI_NAME',
135
        subfields  => 'acdfghjklnpqstvxyz',
181
        subfields  => 'acdefghklnpqstvxyz68',
136
        main_entry => 1
182
        main_entry => 1
137
    },
183
    },
138
    '130' => {
184
    '130' => {
139
        auth_type  => 'UNIF_TITLE',
185
        auth_type  => 'UNIF_TITLE',
140
        subfields  => 'adfghklmnoprstvxyz',
186
        subfields  => 'adfghklmnoprstvxyz68',
187
        main_entry => 1
188
    },
189
    '147' => {
190
        auth_type  => 'NAME_EVENT',
191
        subfields  => 'acdgvxyz68',
141
        main_entry => 1
192
        main_entry => 1
142
    },
193
    },
143
    '148' => {
194
    '148' => {
144
        auth_type => 'CHRON_TERM',
195
        auth_type  => 'CHRON_TERM',
145
        subfields => 'avxyz',
196
        subfields  => 'abvxyz68',
146
        main_entry => 1
197
        main_entry => 1
147
    },
198
    },
148
    '150' => {
199
    '150' => {
149
        auth_type => 'TOPIC_TERM',
200
        auth_type  => 'TOPIC_TERM',
150
        subfields => 'abgvxyz',
201
        subfields  => 'abvxyz68',
151
        main_entry => 1
202
        main_entry => 1
152
    },
203
    },
153
    '151' => {
204
    '151' => {
154
        auth_type => 'GEOG_NAME',
205
        auth_type  => 'GEOG_NAME',
155
        subfields => 'agvxyz',
206
        subfields  => 'avxyz68',
156
        main_entry => 1
207
        main_entry => 1
157
    },
208
    },
158
    '155' => {
209
    '155' => {
159
        auth_type => 'GENRE/FORM',
210
        auth_type  => 'GENRE/FORM',
160
        subfields => 'agvxyz',
211
        subfields  => 'abvxyz68',
161
        main_entry => 1
212
        main_entry => 1
162
    }
213
    },
214
    '162' => {
215
        auth_type  => 'MED_PERFRM',
216
        subfields  => 'a68',
217
        main_entry => 1
218
    },
219
    '180' => {
220
        auth_type => 'TOPIC_TERM',
221
        subfields => 'vxyz68',
222
    },
223
    '181' => {
224
        auth_type => 'GEOGR_NAME',
225
        subfields => 'vxyz68',
226
    },
227
    '182' => {
228
        auth_type => 'CHRON_TERM',
229
        subfields => 'vxyz68',
230
    },
231
    '185' => {
232
        auth_type => 'GENRE/FORM',
233
        subfields => 'vxyz68',
234
    },
163
};
235
};
164
236
165
=head2 subdivisions
237
=head2 subdivisions
Lines 224-229 sub valid_heading_subfield { Link Here
224
    return 0;
296
    return 0;
225
}
297
}
226
298
299
=head2 get_valid_bib_heading_subfields
300
301
=cut
302
303
sub get_valid_bib_heading_subfields {
304
    my $self          = shift;
305
    my $tag           = shift;
306
307
    return $bib_heading_fields->{$tag}->{subfields} // undef;
308
}
309
310
=head2 get_auth_heading_subfields_to_report
311
312
=cut
313
314
sub get_auth_heading_subfields_to_report {
315
    my $self          = shift;
316
    my $tag           = shift;
317
318
    my $subfields = $auth_heading_fields->{$tag}->{subfields} // '';
319
    $subfields =~ s/[68]//;
320
    return $subfields;
321
}
322
227
=head2 parse_heading
323
=head2 parse_heading
228
324
229
Given a field and an indicator to specify if it is an authority field or biblio field we return
325
Given a field and an indicator to specify if it is an authority field or biblio field we return
(-)a/t/db_dependent/AuthoritiesMarc.t (-1 / +27 lines)
Lines 5-13 Link Here
5
5
6
use Modern::Perl;
6
use Modern::Perl;
7
7
8
use Test::More tests => 11;
8
use Test::More tests => 12;
9
use Test::MockModule;
9
use Test::MockModule;
10
use Test::Warn;
10
use Test::Warn;
11
use MARC::Field;
11
use MARC::Record;
12
use MARC::Record;
12
13
13
use t::lib::Mocks;
14
use t::lib::Mocks;
Lines 54-59 $module->mock('GetAuthority', sub { Link Here
54
            [ '151', ' ', ' ', a => 'New York (City)' ],
55
            [ '151', ' ', ' ', a => 'New York (City)' ],
55
            [ '551', ' ', ' ', a => 'New York (State)', w => 'g' ]
56
            [ '551', ' ', ' ', a => 'New York (State)', w => 'g' ]
56
            );
57
            );
58
    } elsif ($authid eq '5') {
59
        $record->add_fields(
60
            [ '001', '5' ],
61
            [ '100', ' ', ' ', a => 'Lastname, Firstname', b => 'b', c => 'c', i => 'i' ]
62
            );
57
    } else {
63
    } else {
58
        undef $record;
64
        undef $record;
59
    }
65
    }
Lines 214-219 subtest 'AddAuthority should respect AUTO_INCREMENT (BZ 18104)' => sub { Link Here
214
    is( $record->field('001')->data, $id3, 'Check updated 001' );
220
    is( $record->field('001')->data, $id3, 'Check updated 001' );
215
};
221
};
216
222
223
subtest 'CompareFieldWithAuthority tests' => sub {
224
    plan tests => 3;
225
226
    t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
227
228
    $builder->build({ source => 'AuthType', value => { authtypecode => 'PERSO_NAME' }});
229
230
    my $field = MARC::Field->new('100', 0, 0, a => 'Lastname, Firstname', b => 'b', c => 'c');
231
232
    ok(C4::AuthoritiesMarc::CompareFieldWithAuthority({'field' => $field, 'authid' => 5}), 'Authority matches');
233
234
    $field->add_subfields(i => 'X');
235
236
    ok(C4::AuthoritiesMarc::CompareFieldWithAuthority({'field' => $field, 'authid' => 5}), 'Compare ignores unlisted subfields');
237
238
    $field->add_subfields(d => 'd');
239
240
    ok(!C4::AuthoritiesMarc::CompareFieldWithAuthority({'field' => $field, 'authid' => 5}), 'Authority does not match');
241
};
242
217
$schema->storage->txn_rollback;
243
$schema->storage->txn_rollback;
218
244
219
$module->unmock('GetAuthority');
245
$module->unmock('GetAuthority');
(-)a/t/db_dependent/AuthoritiesMarc/MARC21.t (+91 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
4
use strict;
5
use warnings;
6
7
use Test::MockModule;
8
use Test::More tests => 2;
9
use MARC::Field;
10
use MARC::Record;
11
12
use t::lib::Mocks;
13
use t::lib::TestBuilder;
14
15
BEGIN {
16
    use_ok('C4::AuthoritiesMarc::MARC21');
17
}
18
19
my $schema  = Koha::Database->new->schema;
20
$schema->storage->txn_begin;
21
my $dbh = C4::Context->dbh;
22
my $builder = t::lib::TestBuilder->new;
23
24
t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
25
26
subtest 'CompareFieldWithAuthority tests' => sub {
27
    plan tests => 3;
28
29
    # We are now going to be testing the authorities hierarchy code, and
30
    # therefore need to pretend that we have consistent data in our database
31
    my $module = new Test::MockModule('C4::AuthoritiesMarc');
32
    $module->mock('GetHeaderAuthority', sub {
33
        return {'authtrees' => ''};
34
    });
35
    $module->mock('AddAuthorityTrees', sub {
36
        return;
37
    });
38
    $module->mock('GetAuthority', sub {
39
        my ($authid) = @_;
40
        my $record = MARC::Record->new();
41
        if ($authid eq '1') {
42
            $record->add_fields(
43
                [ '001', '1' ],
44
                [ '151', ' ', ' ', a => 'United States' ]
45
            );
46
        } elsif ($authid eq '2') {
47
            $record->add_fields(
48
                [ '001', '2' ],
49
                [ '151', ' ', ' ', a => 'New York (State)' ],
50
                [ '551', ' ', ' ', a => 'United States', w => 'g', 9 => '1' ]
51
            );
52
        } elsif ($authid eq '3') {
53
            $record->add_fields(
54
                [ '001', '3' ],
55
                [ '151', ' ', ' ', a => 'New York (City)' ],
56
                [ '551', ' ', ' ', a => 'New York (State)', w => 'g', 9 => '2' ]
57
            );
58
        } elsif ($authid eq '4') {
59
            $record->add_fields(
60
                [ '001', '4' ],
61
                [ '151', ' ', ' ', a => 'New York (City)' ],
62
                [ '551', ' ', ' ', a => 'New York (State)', w => 'g' ]
63
            );
64
        } elsif ($authid eq '5') {
65
            $record->add_fields(
66
                [ '001', '5' ],
67
                [ '100', ' ', ' ', a => 'Lastname, Firstname', b => 'b', c => 'c', i => 'i' ]
68
            );
69
        } else {
70
            undef $record;
71
        }
72
        return $record;
73
    });
74
75
    $dbh->do('DELETE FROM auth_types');
76
    $builder->build({ source => 'AuthType', value => { authtypecode => 'PERSO_NAME' }});
77
78
    my $field = MARC::Field->new('100', 0, 0, a => 'Lastname, Firstname', b => 'b', c => 'c');
79
80
    ok(C4::AuthoritiesMarc::CompareFieldWithAuthority({'field' => $field, 'authid' => 5}), 'Authority matches');
81
82
    $field->add_subfields(i => 'X');
83
84
    ok(C4::AuthoritiesMarc::CompareFieldWithAuthority({'field' => $field, 'authid' => 5}), 'Compare ignores unlisted subfields');
85
86
    $field->add_subfields(d => 'd');
87
88
    ok(!C4::AuthoritiesMarc::CompareFieldWithAuthority({'field' => $field, 'authid' => 5}), 'Authority does not match');
89
};
90
91
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Biblio.t (-1 / +3 lines)
Lines 230-235 sub run_tests { Link Here
230
230
231
    my $marcflavour = shift;
231
    my $marcflavour = shift;
232
    t::lib::Mocks::mock_preference('marcflavour', $marcflavour);
232
    t::lib::Mocks::mock_preference('marcflavour', $marcflavour);
233
    # Authority tests don't interact well with Elasticsearch at the moment due to the fact that there's currently no way to
234
    # roll back ES index changes.
235
    t::lib::Mocks::mock_preference('SearchEngine', 'Zebra');
233
236
234
    my $isbn = '0590353403';
237
    my $isbn = '0590353403';
235
    my $title = 'Foundation';
238
    my $title = 'Foundation';
236
- 

Return to bug 21958