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 922-927 sub BuildSummary { Link Here
922
# construct MARC21 summary
925
# construct MARC21 summary
923
# FIXME - looping over 1XX is questionable
926
# FIXME - looping over 1XX is questionable
924
# since MARC21 authority should have only one 1XX
927
# since MARC21 authority should have only one 1XX
928
        use C4::Heading::MARC21;
929
        my $handler = C4::Heading::MARC21->new();
925
        my $subfields_to_report;
930
        my $subfields_to_report;
926
        foreach my $field ($record->field('1..')) {
931
        foreach my $field ($record->field('1..')) {
927
            my $tag = $field->tag();
932
            my $tag = $field->tag();
Lines 929-959 sub BuildSummary { Link Here
929
# FIXME - 152 is not a good tag to use
934
# FIXME - 152 is not a good tag to use
930
# in MARC21 -- purely local tags really ought to be
935
# in MARC21 -- purely local tags really ought to be
931
# 9XX
936
# 9XX
932
            if ($tag eq '100') {
937
933
                $subfields_to_report = 'abcdefghjklmnopqrstvxyz';
938
            $subfields_to_report = $handler->get_auth_heading_subfields_to_report($tag);
934
            } elsif ($tag eq '110') {
939
935
                $subfields_to_report = 'abcdefghklmnoprstvxyz';
936
            } elsif ($tag eq '111') {
937
                $subfields_to_report = 'acdefghklnpqstvxyz';
938
            } elsif ($tag eq '130') {
939
                $subfields_to_report = 'adfghklmnoprstvxyz';
940
            } elsif ($tag eq '148') {
941
                $subfields_to_report = 'abvxyz';
942
            } elsif ($tag eq '150') {
943
                $subfields_to_report = 'abvxyz';
944
            } elsif ($tag eq '151') {
945
                $subfields_to_report = 'avxyz';
946
            } elsif ($tag eq '155') {
947
                $subfields_to_report = 'abvxyz';
948
            } elsif ($tag eq '180') {
949
                $subfields_to_report = 'vxyz';
950
            } elsif ($tag eq '181') {
951
                $subfields_to_report = 'vxyz';
952
            } elsif ($tag eq '182') {
953
                $subfields_to_report = 'vxyz';
954
            } elsif ($tag eq '185') {
955
                $subfields_to_report = 'vxyz';
956
            }
957
            if ($subfields_to_report) {
940
            if ($subfields_to_report) {
958
                push @authorized, {
941
                push @authorized, {
959
                    heading => $field->as_string($subfields_to_report),
942
                    heading => $field->as_string($subfields_to_report),
Lines 1077-1120 sub GetAuthorizedHeading { Link Here
1077
            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
1060
            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
1078
        }
1061
        }
1079
    } else {
1062
    } else {
1063
        use C4::Heading::MARC21;
1064
        my $handler = C4::Heading::MARC21->new();
1065
1080
        foreach my $field ($record->field('1..')) {
1066
        foreach my $field ($record->field('1..')) {
1081
            my $tag = $field->tag();
1067
            my $subfields = $handler->get_valid_bib_heading_subfields($field->tag());
1082
            next if "152" eq $tag;
1068
            return $field->as_string($subfields) if ($subfields);
1083
# FIXME - 152 is not a good tag to use
1084
# in MARC21 -- purely local tags really ought to be
1085
# 9XX
1086
            if ($tag eq '100') {
1087
                return $field->as_string('abcdefghjklmnopqrstvxyz68');
1088
            } elsif ($tag eq '110') {
1089
                return $field->as_string('abcdefghklmnoprstvxyz68');
1090
            } elsif ($tag eq '111') {
1091
                return $field->as_string('acdefghklnpqstvxyz68');
1092
            } elsif ($tag eq '130') {
1093
                return $field->as_string('adfghklmnoprstvxyz68');
1094
            } elsif ($tag eq '148') {
1095
                return $field->as_string('abvxyz68');
1096
            } elsif ($tag eq '150') {
1097
                return $field->as_string('abvxyz68');
1098
            } elsif ($tag eq '151') {
1099
                return $field->as_string('avxyz68');
1100
            } elsif ($tag eq '155') {
1101
                return $field->as_string('abvxyz68');
1102
            } elsif ($tag eq '180') {
1103
                return $field->as_string('vxyz68');
1104
            } elsif ($tag eq '181') {
1105
                return $field->as_string('vxyz68');
1106
            } elsif ($tag eq '182') {
1107
                return $field->as_string('vxyz68');
1108
            } elsif ($tag eq '185') {
1109
                return $field->as_string('vxyz68');
1110
            } else {
1111
                return $field->as_string();
1112
            }
1113
        }
1069
        }
1114
    }
1070
    }
1115
    return;
1071
    return;
1116
}
1072
}
1117
1073
1074
=head2 CompareFieldWithAuthority
1075
1076
  $match = &CompareFieldWithAuthority({ field => $field, authid => $authid })
1077
1078
Takes a MARC::Field from a bibliographic record and an authid, and returns true if they match.
1079
1080
=cut
1081
1082
sub CompareFieldWithAuthority {
1083
    my $args = shift;
1084
1085
    my $record = GetAuthority($args->{authid});
1086
    return unless (ref $record eq 'MARC::Record');
1087
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
1088
        # UNIMARC has same subfields for bibs and authorities
1089
        foreach my $field ($record->field('2..')) {
1090
            return compare_fields($field, $args->{field}, 'abcdefghijlmnopqrstuvwxyz');
1091
        }
1092
    } else {
1093
        use C4::Heading::MARC21;
1094
        my $handler = C4::Heading::MARC21->new();
1095
1096
        foreach my $field ($record->field('1..')) {
1097
            my $subfields = $handler->get_valid_bib_heading_subfields($field->tag());
1098
            return compare_fields($field, $args->{field}, $subfields) if ($subfields);
1099
        }
1100
    }
1101
    return 0;
1102
}
1103
1118
=head2 BuildAuthHierarchies
1104
=head2 BuildAuthHierarchies
1119
1105
1120
  $text= &BuildAuthHierarchies( $authid, $force)
1106
  $text= &BuildAuthHierarchies( $authid, $force)
Lines 1576-1581 sub get_auth_type_location { Link Here
1576
    }
1562
    }
1577
}
1563
}
1578
1564
1565
=head2 compare_fields
1566
1567
  my match = compare_fields($field1, $field2, 'abcde');
1568
1569
Compares the listed subfields of both fields and return true if they all match
1570
1571
=cut
1572
1573
sub compare_fields {
1574
    my ($field1, $field2, $subfields) = @_;
1575
1576
    foreach my $subfield (split(//, $subfields)) {
1577
        my $subfield1 = $field1->subfield($subfield) // '';
1578
        my $subfield2 = $field2->subfield($subfield) // '';
1579
        return 0 unless $subfield1 eq $subfield2;
1580
    }
1581
    return 1;
1582
}
1583
1584
1579
END { }       # module clean-up code here (global destructor)
1585
END { }       # module clean-up code here (global destructor)
1580
1586
1581
1;
1587
1;
Lines 1586-1591 __END__ Link Here
1586
Koha Development Team <http://koha-community.org/>
1592
Koha Development Team <http://koha-community.org/>
1587
1593
1588
Paul POULAIN paul.poulain@free.fr
1594
Paul POULAIN paul.poulain@free.fr
1595
Ere Maijala ere.maijala@helsinki.fi
1589
1596
1590
=cut
1597
=cut
1591
1598
(-)a/C4/Biblio.pm (-3 / +1 lines)
Lines 714-722 sub _check_valid_auth_link { Link Here
714
    my ( $authid, $field ) = @_;
714
    my ( $authid, $field ) = @_;
715
    require C4::AuthoritiesMarc;
715
    require C4::AuthoritiesMarc;
716
716
717
    my $authorized_heading =
717
    return C4::AuthoritiesMarc::CompareFieldWithAuthority( { 'field' => $field, 'authid' => $authid } );
718
      C4::AuthoritiesMarc::GetAuthorizedHeading( { 'authid' => $authid } ) || '';
719
   return ($field->as_string('abcdefghijklmnopqrstuvwxyz') eq $authorized_heading);
720
}
718
}
721
719
722
=head2 GetBiblioData
720
=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