Bugzilla – Attachment 192103 Details for
Bug 41714
MARC21 authorities thesaurus link hardcoded
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 41714: Add a way to let the authority linker honor frameworks (MARC21)
19a97b1.patch (text/plain), 9.29 KB, created by
Tomás Cohen Arazi (tcohen)
on 2026-01-27 15:44:58 UTC
(
hide
)
Description:
Bug 41714: Add a way to let the authority linker honor frameworks (MARC21)
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2026-01-27 15:44:58 UTC
Size:
9.29 KB
patch
obsolete
>From 19a97b141916942c51552dac26bb6e27f2ee5252 Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Tom=C3=A1s=20Cohen=20Arazi?= <tomascohen@theke.io> >Date: Tue, 27 Jan 2026 12:42:28 -0300 >Subject: [PATCH] Bug 41714: Add a way to let the authority linker honor > frameworks (MARC21) >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >This patchset implements a way to make the authority linker follow the >cataloguing frameworks when it comes to linked authority type. The current >behavior is this for UNIMARC, but in the MARC21 case it just has hardcoded links >(e.g. 650 is always linked to `TOPIC_TERM`). > >This is accomplished by: > >* Replicating what UNIMARC does, in MARC21 >* Moving the code around so both use the same codebase >* Adding tests >* Adding the `LinkerUseFrameworkAuthTypes` system preference for opting into > this new behavior. > >To test: >1. Launch a fresh KTD instance: > $ ktd --proxy --name authorities --search-engine es9 up -d > $ ktd --name authorities --wait-ready 120 >2. On the staff interface (http://authorities-admin.localhost) open record 344 >3. Change the cataloguing framework to the `Default` one and adjust the details > so it can be saved. >4. Edit the `Default` framework to unlink the subfield `650$a` from the > `TOPIC_TERM` thesaurus. >5. Go back to editing the record >=> SUCCESS: Field 650$a can be edited freely (normal behavior for unlinked > subfields) >6. Add the following headings to repeatable `650$a`: > > * YERBA > * MATE > * BOMBILLA > * AGUA CALIENTE > >7. Create a new Authority type called `CUST_TERM` in `Admin > Authority types` > * Make the 'field to copy' be 150 > * Export the `TOPIC_TERM` authority type structure into CSV > * Import the exported authority type onto `CUST_TERM` >=> SUCCESS: `TOPIC_TERM` and `CUST_TERM` are the same thing. >8. Add the following authorities of type `CUST_TERM` > > * YERBA > * MATE > * BOMBILLA > >9. Edit the `Default` framework so `650$a` is now linked to `CUST_TERM` >10. Run: > $ ktd --name authorities --shell > k$ perl misc/link_bibs_to_authorities.pl --bib-limit "biblionumber=344" --auth-limit "authtypecode='CUST_TERM'" -l -g 650 >=> FAIL: You see: > >``` >Bib authority heading linking report >======================================================= >Linker module: C4::Linker::Default >Run started at: 01/27/26 14:40:42 >Run ended at: 01/27/26 14:40:43 >Total run time: 276 ms >Number of bibs checked: 1 >Number of bibs modified: 0 >Number of bibs with errors: 0 >Number of headings linked: 1 >Number of headings unlinked: 4 >Number of headings fuzzily linked: 0 >``` > >This means it kept the currently linked heading, and the other 4 were kept >unliked even though they exist on the `CUST_TERM` thesaurus. > >11. Apply this patchset >12. Run: > k$ updatedatabase > k$ restart_all # just in case >=> SUCCESS: You see a syspref has been added >13. Repeat 10 >=> SUCCESS: Same result! >14. Set the `LinkerUseFrameworkAuthTypes` system preference to `Do` >15. Repeat 10: >=> SUCCESS: Yay! You see: > >``` >Bib authority heading linking report >======================================================= >Linker module: C4::Linker::Default >Run started at: 01/27/26 14:41:15 >Run ended at: 01/27/26 14:41:16 >Total run time: 302 ms >Number of bibs checked: 1 >Number of bibs modified: 1 >Number of bibs with errors: 0 >Number of headings linked: 4 >Number of headings unlinked: 1 >Number of headings fuzzily linked: 0 >``` > >This means *YERBA*, *MATE* and *BOMBILLA* where linked, the existing link was >kept [1] and *AGUA CALIENTE* didn't get linked (of course, as it doesn't exist >in `CUST_TERM`. > >16. Run the tests: > k$ prove t/db_dependent/Headin* >=> SUCCESS: Tests pass! >17. Sign off :-D > >[1] This really depends on how `LinkerKeepStale` is set, but what I describe is >the default behavior. > >Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io> >--- > C4/Heading.pm | 41 +++++++++++++++++++++++++++++++++++++++-- > C4/Heading/MARC21.pm | 38 ++++++++++++++++++++++++++++++++++---- > C4/Heading/UNIMARC.pm | 12 +++--------- > 3 files changed, 76 insertions(+), 15 deletions(-) > >diff --git a/C4/Heading.pm b/C4/Heading.pm >index 7cf7e8c401..c79a2e739b 100644 >--- a/C4/Heading.pm >+++ b/C4/Heading.pm >@@ -31,6 +31,9 @@ use C4::Context; > use Module::Load qw( load ); > use List::Util qw( none first ); > >+# Package-level cache for authority types from frameworks >+my %authority_type_cache; >+ > =head1 NAME > > C4::Heading >@@ -71,7 +74,11 @@ sub new_from_field { > my $frameworkcode = shift; #FIXME this is not used? > my $auth = shift; > my $marcflavour = C4::Context->preference('marcflavour'); >- my $marc_handler = _marc_format_handler($marcflavour); >+ >+ # Enable framework lookup for MARC21 if LinkerUseFrameworkAuthTypes is enabled >+ my $use_frameworks = $marcflavour eq 'MARC21' >+ && C4::Context->preference('LinkerUseFrameworkAuthTypes'); >+ my $marc_handler = _marc_format_handler( $marcflavour, { use_frameworks => $use_frameworks } ); > > return unless $field; > my $tag = $field->tag(); >@@ -304,6 +311,35 @@ sub _filter_diacritics { > > =head1 INTERNAL FUNCTIONS > >+=head2 _load_authority_types_from_frameworks >+ >+Load authority type mappings from marc_subfield_structure. >+Shared by both MARC21 and UNIMARC implementations. >+Results are cached at package level. >+ >+=cut >+ >+sub _load_authority_types_from_frameworks { >+ my $cache_key = shift // 'default'; >+ >+ unless ( exists $authority_type_cache{$cache_key} ) { >+ my $dbh = C4::Context->dbh; >+ my $sth = $dbh->prepare( >+ "SELECT DISTINCT tagfield, authtypecode >+ FROM marc_subfield_structure >+ WHERE frameworkcode = '' AND authtypecode <> ''" >+ ); >+ $sth->execute(); >+ >+ $authority_type_cache{$cache_key} = {}; >+ while ( my ( $tag, $auth_type ) = $sth->fetchrow ) { >+ $authority_type_cache{$cache_key}->{$tag} = $auth_type; >+ } >+ } >+ >+ return $authority_type_cache{$cache_key}; >+} >+ > =head2 _marc_format_handler > > Returns a C4::Heading::MARC21 or C4::Heading::UNIMARC object >@@ -313,9 +349,10 @@ depending on the selected MARC flavour. > > sub _marc_format_handler { > my $marcflavour = uc shift; >+ my $params = shift // {}; > my $pname = "C4::Heading::$marcflavour"; > load $pname; >- return $pname->new(); >+ return $pname->new($params); > } > > =head1 AUTHOR >diff --git a/C4/Heading/MARC21.pm b/C4/Heading/MARC21.pm >index fc7fad7b9c..6976d1931f 100644 >--- a/C4/Heading/MARC21.pm >+++ b/C4/Heading/MARC21.pm >@@ -245,13 +245,40 @@ my %subdivisions = ( > > =head2 new > >- my $marc_handler = C4::Heading::MARC21->new(); >+ my $marc_handler = C4::Heading::MARC21->new(); >+ my $marc_handler = C4::Heading::MARC21->new( { use_frameworks => 1 } ); >+ >+Creates a new MARC21 heading handler. >+ >+If use_frameworks is true, authority types are loaded from marc_subfield_structure >+instead of using the hardcoded defaults. This allows local customization of >+authority types per tag via MARC bibliographic frameworks. > > =cut > > sub new { >- my $class = shift; >- return bless {}, $class; >+ my $class = shift; >+ my $params = shift // {}; >+ >+ my $self = bless {}, $class; >+ >+ if ( $params->{use_frameworks} ) { >+ $self->_load_from_frameworks(); >+ } >+ >+ return $self; >+} >+ >+=head2 _load_from_frameworks >+ >+Load authority type mappings from marc_subfield_structure. >+Uses shared method from C4::Heading with package-level caching. >+ >+=cut >+ >+sub _load_from_frameworks { >+ my $self = shift; >+ $self->{_framework_overrides} = C4::Heading::_load_authority_types_from_frameworks('marc21'); > } > > =head2 valid_heading_tag >@@ -331,7 +358,10 @@ sub parse_heading { > my $heading_fields = $auth ? {%$auth_heading_fields} : {%$bib_heading_fields}; > > my $field_info = $heading_fields->{$tag}; >- my $auth_type = $field_info->{'auth_type'}; >+ >+ # Use framework override if available, otherwise use hardcoded default >+ my $auth_type = $self->{_framework_overrides}->{$tag} // $field_info->{'auth_type'}; >+ > my $thesaurus = > $tag =~ m/6../ > ? _get_subject_thesaurus($field) >diff --git a/C4/Heading/UNIMARC.pm b/C4/Heading/UNIMARC.pm >index 7c2969dce9..9c928359b9 100644 >--- a/C4/Heading/UNIMARC.pm >+++ b/C4/Heading/UNIMARC.pm >@@ -68,17 +68,11 @@ sub new { > my $class = shift; > > unless ( defined $bib_heading_fields ) { >- my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare( >- "SELECT tagfield, authtypecode >- FROM marc_subfield_structure >- WHERE frameworkcode = '' AND authtypecode <> ''" >- ); >- $sth->execute(); >+ my $types = C4::Heading::_load_authority_types_from_frameworks('unimarc'); > $bib_heading_fields = {}; >- while ( my ( $tag, $auth_type ) = $sth->fetchrow ) { >+ foreach my $tag ( keys %$types ) { > $bib_heading_fields->{$tag} = { >- auth_type => $auth_type, >+ auth_type => $types->{$tag}, > subfields => 'abcdefghjklmnopqrstvxyz', > }; > } >-- >2.50.1 (Apple Git-155) >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 41714
:
192058
|
192059
|
192060
|
192101
|
192102
| 192103