Bug 16431: Use Koha::Cache to cache marc subfield structure

The marc subfield structure is currently cached using a global variable
of C4::Context. The infos are retrieved every time a new context is
created.
This patch suggests to use Koha::Cache instead.

To achieve this goal, a new subroutine is created
C4::Biblio::GetMarcSubfieldStructure, it will be called from code which
needs to get the marc subfield structure. GetMarcFromKohaField,
GetMarcSubfieldStructureFromKohaField, TransformKohaToMarc and
_get_inverted_marc_field_map are modified accordingly and the cache is cleared
when the table is updated (from the 3 pl scripts modified by this patch).

The caching done in C4::Context (marcfromkohafield) is removed.

Test plan:
Play with the marc subfield structure (in the administration module),
then add and edit records and make sure everything went fine.

Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Everything works as expected on my functional tests. I'm really happy to see the
patch introduces relevant tests for previously untested functions.

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
This commit is contained in:
Jonathan Druart 2016-05-03 14:34:33 +01:00 committed by Kyle M Hall
parent 1509322c9a
commit 172ebfe520
8 changed files with 143 additions and 176 deletions

View File

@ -88,7 +88,6 @@ sub GetAuthMARCFromKohaField {
my $dbh=C4::Context->dbh;
return 0, 0 unless $kohafield;
$authtypecode="" unless $authtypecode;
my $marcfromkohafield;
my $sth = $dbh->prepare("select tagfield,tagsubfield from auth_subfield_structure where kohafield= ? and authtypecode=? ");
$sth->execute($kohafield,$authtypecode);
my ($tagfield,$tagsubfield) = $sth->fetchrow;

View File

@ -1209,18 +1209,44 @@ C<$frameworkcode> is the framework code.
sub GetUsedMarcStructure {
my $frameworkcode = shift || '';
my $query = qq/
my $query = q{
SELECT *
FROM marc_subfield_structure
WHERE tab > -1
AND frameworkcode = ?
ORDER BY tagfield, tagsubfield
/;
};
my $sth = C4::Context->dbh->prepare($query);
$sth->execute($frameworkcode);
return $sth->fetchall_arrayref( {} );
}
=head2 GetMarcSubfieldStructure
=cut
sub GetMarcSubfieldStructure {
my ( $frameworkcode ) = @_;
$frameworkcode //= '';
my $cache = Koha::Cache->get_instance();
my $cache_key = "MarcSubfieldStructure-$frameworkcode";
my $cached = $cache->get_from_cache($cache_key);
return $cached if $cached;
my $dbh = C4::Context->dbh;
my $subfield_structure = $dbh->selectall_hashref( q|
SELECT *
FROM marc_subfield_structure
WHERE frameworkcode = ?
AND kohafield > ''
|, 'kohafield', {}, $frameworkcode );
$cache->set_in_cache( $cache_key, $subfield_structure );
return $subfield_structure;
}
=head2 GetMarcFromKohaField
($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
@ -1231,14 +1257,10 @@ for the given frameworkcode or default framework if $frameworkcode is missing
=cut
sub GetMarcFromKohaField {
my $kohafield = shift;
my $frameworkcode = shift || '';
my ( $kohafield, $frameworkcode ) = @_;
return (0, undef) unless $kohafield;
my $relations = C4::Context->marcfromkohafield;
if ( my $mf = $relations->{$frameworkcode}->{$kohafield} ) {
return @$mf;
}
return (0, undef);
my $mss = GetMarcSubfieldStructure( $frameworkcode );
return ( $mss->{$kohafield}{tagfield}, $mss->{$kohafield}{tagsubfield} );
}
=head2 GetMarcSubfieldStructureFromKohaField
@ -1253,24 +1275,14 @@ $frameworkcode is optional. If not given, then the default framework is used.
=cut
sub GetMarcSubfieldStructureFromKohaField {
my ($kohafield, $frameworkcode) = @_;
my ( $kohafield, $frameworkcode ) = @_;
return undef unless $kohafield;
$frameworkcode //= '';
return unless $kohafield;
my $dbh = C4::Context->dbh;
my $query = qq{
SELECT *
FROM marc_subfield_structure
WHERE kohafield = ?
AND frameworkcode = ?
};
my $sth = $dbh->prepare($query);
$sth->execute($kohafield, $frameworkcode);
my $result = $sth->fetchrow_hashref;
$sth->finish;
return $result;
my $mss = GetMarcSubfieldStructure( $frameworkcode );
return exists $mss->{$kohafield}
? $mss->{$kohafield}
: undef;
}
=head2 GetMarcBiblio
@ -2231,17 +2243,18 @@ sub TransformKohaToMarc {
my $hash = shift;
my $record = MARC::Record->new();
SetMarcUnicodeFlag( $record, C4::Context->preference("marcflavour") );
my $db_to_marc = C4::Context->marcfromkohafield;
# FIXME Do not we want to get the marc subfield structure for the biblio framework?
my $mss = GetMarcSubfieldStructure();
my $tag_hr = {};
while ( my ($name, $value) = each %$hash ) {
next unless my $dtm = $db_to_marc->{''}->{$name};
next unless ( scalar( @$dtm ) );
my ($tag, $letter) = @$dtm;
$tag .= '';
while ( my ($kohafield, $value) = each %$hash ) {
next unless exists $mss->{$kohafield};
next unless $mss->{$kohafield};
my $tagfield = $mss->{$kohafield}{tagfield} . '';
my $tagsubfield = $mss->{$kohafield}{tagsubfield};
foreach my $value ( split(/\s?\|\s?/, $value, -1) ) {
next if $value eq '';
$tag_hr->{$tag} //= [];
push @{$tag_hr->{$tag}}, [($letter, $value)];
$tag_hr->{$tagfield} //= [];
push @{$tag_hr->{$tagfield}}, [($tagsubfield, $value)];
}
}
foreach my $tag (sort keys %$tag_hr) {
@ -2606,9 +2619,6 @@ sub TransformHtmlToMarc {
return $record;
}
# cache inverted MARC field map
our $inverted_field_map;
=head2 TransformMarcToKoha
$result = TransformMarcToKoha( $record, $frameworkcode )
@ -2632,9 +2642,7 @@ sub TransformMarcToKoha {
$limit_table = $limit_table || 0;
$frameworkcode = '' unless defined $frameworkcode;
unless ( defined $inverted_field_map ) {
$inverted_field_map = _get_inverted_marc_field_map();
}
my $inverted_field_map = _get_inverted_marc_field_map($frameworkcode);
my %tables = ();
if ( defined $limit_table && $limit_table eq 'items' ) {
@ -2648,9 +2656,9 @@ sub TransformMarcToKoha {
# traverse through record
MARCFIELD: foreach my $field ( $record->fields() ) {
my $tag = $field->tag();
next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
next MARCFIELD unless exists $inverted_field_map->{$tag};
if ( $field->is_control_field() ) {
my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
my $kohafields = $inverted_field_map->{$tag}->{list};
ENTRY: foreach my $entry ( @{$kohafields} ) {
my ( $subfield, $table, $column ) = @{$entry};
next ENTRY unless exists $tables{$table};
@ -2668,9 +2676,9 @@ sub TransformMarcToKoha {
# deal with subfields
MARCSUBFIELD: foreach my $sf ( $field->subfields() ) {
my $code = $sf->[0];
next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
next MARCSUBFIELD unless exists $inverted_field_map->{$tag}->{sfs}->{$code};
my $value = $sf->[1];
SFENTRY: foreach my $entry ( @{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} } ) {
SFENTRY: foreach my $entry ( @{ $inverted_field_map->{$tag}->{sfs}->{$code} } ) {
my ( $table, $column ) = @{$entry};
next SFENTRY unless exists $tables{$table};
my $key = _disambiguate( $table, $column );
@ -2713,18 +2721,17 @@ sub TransformMarcToKoha {
}
sub _get_inverted_marc_field_map {
my ( $frameworkcode ) = @_;
my $field_map = {};
my $relations = C4::Context->marcfromkohafield;
my $mss = GetMarcSubfieldStructure( $frameworkcode );
foreach my $frameworkcode ( keys %{$relations} ) {
foreach my $kohafield ( keys %{ $relations->{$frameworkcode} } ) {
next unless @{ $relations->{$frameworkcode}->{$kohafield} }; # not all columns are mapped to MARC tag & subfield
my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
my ( $table, $column ) = split /[.]/, $kohafield, 2;
push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
}
foreach my $kohafield ( keys %{ $mss } ) {
next unless exists $mss->{$kohafield}; # not all columns are mapped to MARC tag & subfield
my $tag = $mss->{$kohafield}{tagfield};
my $subfield = $mss->{$kohafield}{tagsubfield};
my ( $table, $column ) = split /[.]/, $kohafield, 2;
push @{ $field_map->{$tag}->{list} }, [ $subfield, $table, $column ];
push @{ $field_map->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
}
return $field_map;
}

View File

@ -373,7 +373,6 @@ sub new {
return if !defined($self->{"config"});
$self->{"Zconn"} = undef; # Zebra Connections
$self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
$self->{"userenv"} = undef; # User env
$self->{"activeuser"} = undef; # current active user
$self->{"shelves"} = undef;
@ -931,45 +930,6 @@ sub _new_queryparser {
return;
}
=head2 marcfromkohafield
$dbh = C4::Context->marcfromkohafield;
Returns a hash with marcfromkohafield.
This hash is cached for future use: if you call
C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
=cut
#'
sub marcfromkohafield
{
my $retval = {};
# If the hash already exists, return it.
return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
# No hash. Create one.
$context->{"marcfromkohafield"} = &_new_marcfromkohafield();
return $context->{"marcfromkohafield"};
}
# _new_marcfromkohafield
sub _new_marcfromkohafield
{
my $dbh = C4::Context->dbh;
my $marcfromkohafield;
my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
$sth->execute;
while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
my $retval = {};
$marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
}
return $marcfromkohafield;
}
=head2 userenv
C4::Context->userenv;

View File

@ -81,6 +81,7 @@ if ( $op eq 'add_form' ) {
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$op = 'list';
} elsif ( $op eq 'delete_confirm' ) {
my $framework = Koha::BiblioFrameworks->find($frameworkcode);
@ -111,6 +112,7 @@ if ( $op eq 'add_form' ) {
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$op = 'list';
}

View File

@ -342,6 +342,7 @@ elsif ( $op eq 'add_validate' ) {
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
print $input->redirect("/cgi-bin/koha/admin/marc_subfields_structure.pl?tagfield=$tagfield&amp;frameworkcode=$frameworkcode");
exit;
@ -386,6 +387,7 @@ elsif ( $op eq 'delete_confirmed' ) {
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
print $input->redirect("/cgi-bin/koha/admin/marc_subfields_structure.pl?tagfield=$tagfield&amp;frameworkcode=$frameworkcode");
exit;

View File

@ -165,6 +165,7 @@ if ($op eq 'add_form') {
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
}
print $input->redirect("/cgi-bin/koha/admin/marctagstructure.pl?searchfield=$tagfield&frameworkcode=$frameworkcode");
exit;
@ -192,6 +193,7 @@ if ($op eq 'add_form') {
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
}
$template->param(
searchfield => $searchfield,
@ -358,5 +360,6 @@ sub duplicate_framework {
$cache->clear_from_cache("MarcStructure-0-$newframeworkcode");
$cache->clear_from_cache("MarcStructure-1-$newframeworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
}

View File

@ -33,10 +33,63 @@ my $dbh = C4::Context->dbh;
$dbh->{AutoCommit} = 0;
$dbh->{RaiseError} = 1;
# Mocking variables
my $context = new Test::MockModule('C4::Context');
subtest 'GetMarcSubfieldStructureFromKohaField' => sub {
plan tests => 23;
mock_marcfromkohafield();
my @columns = qw(
tagfield tagsubfield liblibrarian libopac repeatable mandatory kohafield tab
authorised_value authtypecode value_builder isurl hidden frameworkcode
seealso link defaultvalue maxlength
);
# biblio.biblionumber must be mapped so this should return something
my $marc_subfield_structure = GetMarcSubfieldStructureFromKohaField('biblio.biblionumber', '');
ok(defined $marc_subfield_structure, "There is a result");
is(ref $marc_subfield_structure, "HASH", "Result is a hashref");
foreach my $col (@columns) {
ok(exists $marc_subfield_structure->{$col}, "Hashref contains key '$col'");
}
is($marc_subfield_structure->{kohafield}, 'biblio.biblionumber', "Result is the good result");
like($marc_subfield_structure->{tagfield}, qr/^\d{3}$/, "tagfield is a valid tagfield");
# foo.bar does not exist so this should return undef
$marc_subfield_structure = GetMarcSubfieldStructureFromKohaField('foo.bar', '');
is($marc_subfield_structure, undef, "invalid kohafield returns undef");
};
# Mocking variables
my $biblio_module = new Test::MockModule('C4::Biblio');
$biblio_module->mock(
'GetMarcSubfieldStructure',
sub {
my ($self) = shift;
if ( C4::Context->preference('marcflavour') eq 'MARC21'
|| C4::Context->preference('marcflavour') eq 'NORMARC' ) {
return {
'biblio.title' => { tagfield => '245', tagsubfield => 'a' },
'biblio.biblionumber' => { tagfield => '999', tagsubfield => 'c' },
'biblioitems.isbn' => { tagfield => '020', tagsubfield => 'a' },
'biblioitems.issn' => { tagfield => '022', tagsubfield => 'a' },
'biblioitems.biblioitemnumber' => { tagfield => '999', tagsubfield => 'd' },
'items.itemnumber' => { tagfield => '952', tagsubfield => '9' },
};
} elsif ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
return {
'biblio.title' => { tagfield => '200', tagsubfield => 'a' },
'biblio.biblionumber' => { tagfield => '999', tagsubfield => 'c' },
'biblioitems.isbn' => { tagfield => '010', tagsubfield => 'a' },
'biblioitems.issn' => { tagfield => '011', tagsubfield => 'a' },
'biblioitems.biblioitemnumber' => { tagfield => '090', tagsubfield => 'a' },
'items.itemnumber' => { tagfield => '995', tagsubfield => '9' },
};
}
}
);
my $currency = new Test::MockModule('Koha::Acquisition::Currencies');
$currency->mock(
@ -54,10 +107,6 @@ $currency->mock(
sub run_tests {
# Undef C4::Biblio::inverted_field_map to avoid problems introduced
# by caching in TransformMarcToKoha
undef $C4::Biblio::inverted_field_map;
my $marcflavour = shift;
t::lib::Mocks::mock_preference('marcflavour', $marcflavour);
@ -226,39 +275,6 @@ sub run_tests {
'Check the number of returned notes of GetMarcNotes' );
}
sub mock_marcfromkohafield {
$context->mock('marcfromkohafield',
sub {
my ( $self ) = shift;
if ( C4::Context->preference('marcflavour') eq 'MARC21' ||
C4::Context->preference('marcflavour') eq 'NORMARC' ) {
return {
'' => {
'biblio.title' => [ '245', 'a' ],
'biblio.biblionumber' => [ '999', 'c' ],
'biblioitems.isbn' => [ '020', 'a' ],
'biblioitems.issn' => [ '022', 'a' ],
'biblioitems.biblioitemnumber' => [ '999', 'd' ]
}
};
} elsif ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
return {
'' => {
'biblio.title' => [ '200', 'a' ],
'biblio.biblionumber' => [ '999', 'c' ],
'biblioitems.isbn' => [ '010', 'a' ],
'biblioitems.issn' => [ '011', 'a' ],
'biblioitems.biblioitemnumber' => [ '090', 'a' ]
}
};
}
});
}
sub create_title_field {
my ( $title, $marcflavour ) = @_;
@ -307,31 +323,6 @@ subtest 'NORMARC' => sub {
$dbh->rollback;
};
subtest 'GetMarcSubfieldStructureFromKohaField' => sub {
plan tests => 23;
my @columns = qw(
tagfield tagsubfield liblibrarian libopac repeatable mandatory kohafield tab
authorised_value authtypecode value_builder isurl hidden frameworkcode
seealso link defaultvalue maxlength
);
# biblio.biblionumber must be mapped so this should return something
my $marc_subfield_structure = GetMarcSubfieldStructureFromKohaField('biblio.biblionumber', '');
ok(defined $marc_subfield_structure, "There is a result");
is(ref $marc_subfield_structure, "HASH", "Result is a hashref");
foreach my $col (@columns) {
ok(exists $marc_subfield_structure->{$col}, "Hashref contains key '$col'");
}
is($marc_subfield_structure->{kohafield}, 'biblio.biblionumber', "Result is the good result");
like($marc_subfield_structure->{tagfield}, qr/^\d{3}$/, "tagfield is a valid tagfield");
# foo.bar does not exist so this should return undef
$marc_subfield_structure = GetMarcSubfieldStructureFromKohaField('foo.bar', '');
is($marc_subfield_structure, undef, "invalid kohafield returns undef");
};
subtest 'IsMarcStructureInternal' => sub {
plan tests => 6;
my $tagslib = GetMarcStructure();

View File

@ -372,15 +372,19 @@ subtest 'SearchItems test' => sub {
}
ok($found, "item1 found");
my ($itemfield) = GetMarcFromKohaField('items.itemnumber', '');
my $frameworkcode = q||;
my ($itemfield) = GetMarcFromKohaField('items.itemnumber', $frameworkcode);
# Create item subfield 'z' without link
$dbh->do('DELETE FROM marc_subfield_structure WHERE tagfield=? AND tagsubfield="z" AND frameworkcode=""', undef, $itemfield);
$dbh->do('INSERT INTO marc_subfield_structure (tagfield, tagsubfield, frameworkcode) VALUES (?, "z", "")', undef, $itemfield);
$dbh->do('DELETE FROM marc_subfield_structure WHERE tagfield=? AND tagsubfield="z" AND frameworkcode=?', undef, $itemfield, $frameworkcode);
$dbh->do('INSERT INTO marc_subfield_structure (tagfield, tagsubfield, frameworkcode) VALUES (?, "z", ?)', undef, $itemfield, $frameworkcode);
# Clear cache
$C4::Context::context->{marcfromkohafield} = undef;
$C4::Biblio::inverted_field_map = undef;
my $cache = Koha::Cache->get_instance();
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
my $item3_record = new MARC::Record;
$item3_record->append_fields(
@ -400,12 +404,14 @@ subtest 'SearchItems test' => sub {
# Link $z to items.itemnotes (and make sure there is no other subfields
# linked to it)
$dbh->do('DELETE FROM marc_subfield_structure WHERE kohafield="items.itemnotes" AND frameworkcode=""', undef, $itemfield);
$dbh->do('UPDATE marc_subfield_structure SET kohafield="items.itemnotes" WHERE tagfield=? AND tagsubfield="z" AND frameworkcode=""', undef, $itemfield);
$dbh->do('DELETE FROM marc_subfield_structure WHERE kohafield="items.itemnotes" AND frameworkcode=?', undef, $itemfield, $frameworkcode);
$dbh->do('UPDATE marc_subfield_structure SET kohafield="items.itemnotes" WHERE tagfield=? AND tagsubfield="z" AND frameworkcode=?', undef, $itemfield, $frameworkcode);
# Clear cache
$C4::Context::context->{marcfromkohafield} = undef;
$C4::Biblio::inverted_field_map = undef;
$cache->clear_from_cache("MarcStructure-0-$frameworkcode");
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-$frameworkcode");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
ModItemFromMarc($item3_record, $biblionumber, $item3_itemnumber);
@ -559,10 +565,6 @@ subtest 'C4::Items::_build_default_values_for_mod_marc' => sub {
$schema->storage->txn_begin();
# Clear cache
$C4::Context::context->{marcfromkohafield} = undef;
$C4::Biblio::inverted_field_map = undef;
my $builder = t::lib::TestBuilder->new;
my $framework = $builder->build({
source => 'BiblioFramework',
@ -642,10 +644,11 @@ subtest 'C4::Items::_build_default_values_for_mod_marc' => sub {
|, undef, $framework->{frameworkcode} );
# And make sure the caches are cleared
$C4::Context::context->{marcfromkohafield} = undef;
$C4::Biblio::inverted_field_map = undef;
my $cache = Koha::Cache->get_instance();
$cache->clear_from_cache("default_value_for_mod_marc-" . $framework->{frameworkcode} );
my $cache = Koha::Cache->get_instance();
$cache->clear_from_cache("MarcStructure-0-" . $framework->{frameworkcode});
$cache->clear_from_cache("MarcStructure-1-" . $framework->{frameworkcode});
$cache->clear_from_cache("default_value_for_mod_marc-" . $framework->{frameworkcode});
$cache->clear_from_cache("MarcSubfieldStructure-" . $framework->{frameworkcode});
# Update the MARC field with another value
$item_record->delete_fields( $barcode_field );