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 337-346 sub GuessAuthTypeCode { Link Here
337
        '110'=>{authtypecode=>'CORPO_NAME'},
338
        '110'=>{authtypecode=>'CORPO_NAME'},
338
        '111'=>{authtypecode=>'MEETI_NAME'},
339
        '111'=>{authtypecode=>'MEETI_NAME'},
339
        '130'=>{authtypecode=>'UNIF_TITLE'},
340
        '130'=>{authtypecode=>'UNIF_TITLE'},
341
        '147'=>{authtypecode=>'NAME_EVENT'},
340
        '148'=>{authtypecode=>'CHRON_TERM'},
342
        '148'=>{authtypecode=>'CHRON_TERM'},
341
        '150'=>{authtypecode=>'TOPIC_TERM'},
343
        '150'=>{authtypecode=>'TOPIC_TERM'},
342
        '151'=>{authtypecode=>'GEOGR_NAME'},
344
        '151'=>{authtypecode=>'GEOGR_NAME'},
343
        '155'=>{authtypecode=>'GENRE/FORM'},
345
        '155'=>{authtypecode=>'GENRE/FORM'},
346
        '162'=>{authtypecode=>'MED_PERFRM'},
344
        '180'=>{authtypecode=>'GEN_SUBDIV'},
347
        '180'=>{authtypecode=>'GEN_SUBDIV'},
345
        '181'=>{authtypecode=>'GEO_SUBDIV'},
348
        '181'=>{authtypecode=>'GEO_SUBDIV'},
346
        '182'=>{authtypecode=>'CHRON_SUBD'},
349
        '182'=>{authtypecode=>'CHRON_SUBD'},
Lines 916-921 sub BuildSummary { Link Here
916
# construct MARC21 summary
919
# construct MARC21 summary
917
# FIXME - looping over 1XX is questionable
920
# FIXME - looping over 1XX is questionable
918
# since MARC21 authority should have only one 1XX
921
# since MARC21 authority should have only one 1XX
922
        use C4::Heading::MARC21;
923
        my $handler = C4::Heading::MARC21->new();
919
        my $subfields_to_report;
924
        my $subfields_to_report;
920
        foreach my $field ($record->field('1..')) {
925
        foreach my $field ($record->field('1..')) {
921
            my $tag = $field->tag();
926
            my $tag = $field->tag();
Lines 923-953 sub BuildSummary { Link Here
923
# FIXME - 152 is not a good tag to use
928
# FIXME - 152 is not a good tag to use
924
# in MARC21 -- purely local tags really ought to be
929
# in MARC21 -- purely local tags really ought to be
925
# 9XX
930
# 9XX
926
            if ($tag eq '100') {
931
927
                $subfields_to_report = 'abcdefghjklmnopqrstvxyz';
932
            $subfields_to_report = $handler->get_auth_heading_subfields_to_report($tag);
928
            } elsif ($tag eq '110') {
933
929
                $subfields_to_report = 'abcdefghklmnoprstvxyz';
930
            } elsif ($tag eq '111') {
931
                $subfields_to_report = 'acdefghklnpqstvxyz';
932
            } elsif ($tag eq '130') {
933
                $subfields_to_report = 'adfghklmnoprstvxyz';
934
            } elsif ($tag eq '148') {
935
                $subfields_to_report = 'abvxyz';
936
            } elsif ($tag eq '150') {
937
                $subfields_to_report = 'abvxyz';
938
            } elsif ($tag eq '151') {
939
                $subfields_to_report = 'avxyz';
940
            } elsif ($tag eq '155') {
941
                $subfields_to_report = 'abvxyz';
942
            } elsif ($tag eq '180') {
943
                $subfields_to_report = 'vxyz';
944
            } elsif ($tag eq '181') {
945
                $subfields_to_report = 'vxyz';
946
            } elsif ($tag eq '182') {
947
                $subfields_to_report = 'vxyz';
948
            } elsif ($tag eq '185') {
949
                $subfields_to_report = 'vxyz';
950
            }
951
            if ($subfields_to_report) {
934
            if ($subfields_to_report) {
952
                push @authorized, {
935
                push @authorized, {
953
                    heading => $field->as_string($subfields_to_report),
936
                    heading => $field->as_string($subfields_to_report),
Lines 1071-1114 sub GetAuthorizedHeading { Link Here
1071
            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
1054
            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
1072
        }
1055
        }
1073
    } else {
1056
    } else {
1057
        use C4::Heading::MARC21;
1058
        my $handler = C4::Heading::MARC21->new();
1059
1074
        foreach my $field ($record->field('1..')) {
1060
        foreach my $field ($record->field('1..')) {
1075
            my $tag = $field->tag();
1061
            my $subfields = $handler->get_valid_bib_heading_subfields($field->tag());
1076
            next if "152" eq $tag;
1062
            return $field->as_string($subfields) if ($subfields);
1077
# FIXME - 152 is not a good tag to use
1078
# in MARC21 -- purely local tags really ought to be
1079
# 9XX
1080
            if ($tag eq '100') {
1081
                return $field->as_string('abcdefghjklmnopqrstvxyz68');
1082
            } elsif ($tag eq '110') {
1083
                return $field->as_string('abcdefghklmnoprstvxyz68');
1084
            } elsif ($tag eq '111') {
1085
                return $field->as_string('acdefghklnpqstvxyz68');
1086
            } elsif ($tag eq '130') {
1087
                return $field->as_string('adfghklmnoprstvxyz68');
1088
            } elsif ($tag eq '148') {
1089
                return $field->as_string('abvxyz68');
1090
            } elsif ($tag eq '150') {
1091
                return $field->as_string('abvxyz68');
1092
            } elsif ($tag eq '151') {
1093
                return $field->as_string('avxyz68');
1094
            } elsif ($tag eq '155') {
1095
                return $field->as_string('abvxyz68');
1096
            } elsif ($tag eq '180') {
1097
                return $field->as_string('vxyz68');
1098
            } elsif ($tag eq '181') {
1099
                return $field->as_string('vxyz68');
1100
            } elsif ($tag eq '182') {
1101
                return $field->as_string('vxyz68');
1102
            } elsif ($tag eq '185') {
1103
                return $field->as_string('vxyz68');
1104
            } else {
1105
                return $field->as_string();
1106
            }
1107
        }
1063
        }
1108
    }
1064
    }
1109
    return;
1065
    return;
1110
}
1066
}
1111
1067
1068
=head2 CompareFieldWithAuthority
1069
1070
  $match = &CompareFieldWithAuthority({ field => $field, authid => $authid })
1071
1072
Takes a MARC::Field from a bibliographic record and an authid, and returns true if they match.
1073
1074
=cut
1075
1076
sub CompareFieldWithAuthority {
1077
    my $args = shift;
1078
1079
    my $record = GetAuthority($args->{authid});
1080
    return unless (ref $record eq 'MARC::Record');
1081
    if (C4::Context->preference('marcflavour') eq 'UNIMARC') {
1082
        # UNIMARC has same subfields for bibs and authorities
1083
        foreach my $field ($record->field('2..')) {
1084
            return compare_fields($field, $args->{field}, 'abcdefghijlmnopqrstuvwxyz');
1085
        }
1086
    } else {
1087
        use C4::Heading::MARC21;
1088
        my $handler = C4::Heading::MARC21->new();
1089
1090
        foreach my $field ($record->field('1..')) {
1091
            my $subfields = $handler->get_valid_bib_heading_subfields($field->tag());
1092
            return compare_fields($field, $args->{field}, $subfields) if ($subfields);
1093
        }
1094
    }
1095
    return 0;
1096
}
1097
1112
=head2 BuildAuthHierarchies
1098
=head2 BuildAuthHierarchies
1113
1099
1114
  $text= &BuildAuthHierarchies( $authid, $force)
1100
  $text= &BuildAuthHierarchies( $authid, $force)
Lines 1570-1575 sub get_auth_type_location { Link Here
1570
    }
1556
    }
1571
}
1557
}
1572
1558
1559
=head2 compare_fields
1560
1561
  my match = compare_fields($field1, $field2, 'abcde');
1562
1563
Compares the listed subfields of both fields and return true if they all match
1564
1565
=cut
1566
1567
sub compare_fields {
1568
    my ($field1, $field2, $subfields) = @_;
1569
1570
    foreach my $subfield (split(//, $subfields)) {
1571
        my $subfield1 = $field1->subfield($subfield) // '';
1572
        my $subfield2 = $field2->subfield($subfield) // '';
1573
        return 0 unless $subfield1 eq $subfield2;
1574
    }
1575
    return 1;
1576
}
1577
1578
1573
END { }       # module clean-up code here (global destructor)
1579
END { }       # module clean-up code here (global destructor)
1574
1580
1575
1;
1581
1;
Lines 1580-1585 __END__ Link Here
1580
Koha Development Team <http://koha-community.org/>
1586
Koha Development Team <http://koha-community.org/>
1581
1587
1582
Paul POULAIN paul.poulain@free.fr
1588
Paul POULAIN paul.poulain@free.fr
1589
Ere Maijala ere.maijala@helsinki.fi
1583
1590
1584
=cut
1591
=cut
1585
1592
(-)a/C4/Biblio.pm (-3 / +1 lines)
Lines 633-641 sub _check_valid_auth_link { Link Here
633
    my ( $authid, $field ) = @_;
633
    my ( $authid, $field ) = @_;
634
    require C4::AuthoritiesMarc;
634
    require C4::AuthoritiesMarc;
635
635
636
    my $authorized_heading =
636
    return C4::AuthoritiesMarc::CompareFieldWithAuthority( { 'field' => $field, 'authid' => $authid } );
637
      C4::AuthoritiesMarc::GetAuthorizedHeading( { 'authid' => $authid } ) || '';
638
   return ($field->as_string('abcdefghijklmnopqrstuvwxyz') eq $authorized_heading);
639
}
637
}
640
638
641
=head2 GetBiblioData
639
=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 => 9;
8
use Test::More tests => 10;
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-217 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;
(-)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 203-208 sub run_tests { Link Here
203
203
204
    my $marcflavour = shift;
204
    my $marcflavour = shift;
205
    t::lib::Mocks::mock_preference('marcflavour', $marcflavour);
205
    t::lib::Mocks::mock_preference('marcflavour', $marcflavour);
206
    # Authority tests don't interact well with Elasticsearch at the moment due to the fact that there's currently no way to
207
    # roll back ES index changes.
208
    t::lib::Mocks::mock_preference('SearchEngine', 'Zebra');
206
209
207
    my $isbn = '0590353403';
210
    my $isbn = '0590353403';
208
    my $title = 'Foundation';
211
    my $title = 'Foundation';
209
- 

Return to bug 21958