#
# This file is part of Koha.
#
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
#
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
use strict;
use warnings;
use Carp;
-# use utf8;
+use Encode qw( decode is_utf8 );
use MARC::Record;
use MARC::File::USMARC;
use MARC::File::XML;
use Module::Load::Conditional qw(can_load);
use C4::Koha;
-use C4::Dates qw/format_date/;
use C4::Log; # logaction
use C4::Budgets;
use C4::ClassSource;
use C4::Linker;
use C4::OAI::Sets;
+use Koha::Cache;
+use Koha::Authority::Types;
+
use vars qw($VERSION @ISA @EXPORT);
BEGIN {
# to get something
push @EXPORT, qw(
- &GetBiblio
- &GetBiblioData
- &GetBiblioItemData
- &GetBiblioItemInfosOf
- &GetBiblioItemByBiblioNumber
- &GetBiblioFromItemNumber
- &GetBiblionumberFromItemnumber
+ GetBiblio
+ GetBiblioData
+ GetMarcBiblio
+ GetBiblioItemData
+ GetBiblioItemInfosOf
+ GetBiblioItemByBiblioNumber
+ GetBiblioFromItemNumber
+ GetBiblionumberFromItemnumber
&GetRecordValue
&GetFieldMapping
&GetMarcISBN
&GetMarcISSN
&GetMarcSubjects
- &GetMarcBiblio
&GetMarcAuthors
&GetMarcSeries
&GetMarcHosts
# Internal functions
# those functions are exported but should not be used
- # they are usefull is few circumstances, so are exported.
- # but don't use them unless you're a core developer ;-)
+ # they are useful in a few circumstances, so they are exported,
+ # but don't use them unless you are a core developer ;-)
push @EXPORT, qw(
&ModBiblioMarc
);
);
}
-eval {
- if (C4::Context->ismemcached) {
- require Memoize::Memcached;
- import Memoize::Memcached qw(memoize_memcached);
-
- memoize_memcached( 'GetMarcStructure',
- memcached => C4::Context->memcached);
- }
-};
-
=head1 NAME
C4::Biblio - cataloging management functions
$results{'linked'}->{ $heading->display_form() }++;
}
else {
- my $authtypedata =
- C4::AuthoritiesMarc::GetAuthType( $heading->auth_type() );
+ my $authority_type = Koha::Authority::Types->find( $heading->auth_type() );
my $marcrecordauth = MARC::Record->new();
if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
$marcrecordauth->leader(' nz a22 o 4500');
$field->delete_subfield( code => '9' )
if defined $current_link;
my $authfield =
- MARC::Field->new( $authtypedata->{auth_tag_to_report},
+ MARC::Field->new( $authority_type->auth_tag_to_report,
'', '', "a" => "" . $field->subfield('a') );
map {
$authfield->add_subfields( $_->[0] => $_->[1] )
}
Check whether the specified heading-auth link is valid without reference
-to Zebra/Solr. Ideally this code would be in C4::Heading, but that won't be
+to Zebra. Ideally this code would be in C4::Heading, but that won't be
possible until we have de-cycled C4::AuthoritiesMarc, so this is the
safest place.
=cut
-# cache for results of GetMarcStructure -- needed
-# for batch jobs
-our $marc_structure_cache;
-
sub GetMarcStructure {
my ( $forlibrarian, $frameworkcode ) = @_;
my $dbh = C4::Context->dbh;
$frameworkcode = "" unless $frameworkcode;
- if ( defined $marc_structure_cache and exists $marc_structure_cache->{$forlibrarian}->{$frameworkcode} ) {
- return $marc_structure_cache->{$forlibrarian}->{$frameworkcode};
- }
+ $forlibrarian = $forlibrarian ? 1 : 0;
+ my $cache = Koha::Cache->get_instance();
+ my $cache_key = "MarcStructure-$forlibrarian-$frameworkcode";
+ my $cached = $cache->get_from_cache($cache_key);
+ return $cached if $cached;
- # my $sth = $dbh->prepare(
- # "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
- # $sth->execute($frameworkcode);
- # my ($total) = $sth->fetchrow;
- # $frameworkcode = "" unless ( $total > 0 );
my $sth = $dbh->prepare(
"SELECT tagfield,liblibrarian,libopac,mandatory,repeatable
FROM marc_tag_structure
$res->{$tag}->{$subfield}->{maxlength} = $maxlength;
}
- $marc_structure_cache->{$forlibrarian}->{$frameworkcode} = $res;
-
+ $cache->set_in_cache($cache_key, $res);
return $res;
}
=head2 GetMarcBiblio
- my $record = GetMarcBiblio($biblionumber, [$embeditems]);
+ my $record = GetMarcBiblio($biblionumber, [$embeditems], [$opac]);
+
+Returns MARC::Record representing a biblio record, or C<undef> if the
+biblionumber doesn't exist.
+
+=over 4
+
+=item C<$biblionumber>
+
+the biblionumber
-Returns MARC::Record representing bib identified by
-C<$biblionumber>. If no bib exists, returns undef.
-C<$embeditems>. If set to true, items data are included.
-The MARC record contains biblio data, and items data if $embeditems is set to true.
+=item C<$embeditems>
+
+set to true to include item information.
+
+=item C<$opac>
+
+set to true to make the result suited for OPAC view. This causes things like
+OpacHiddenItems to be applied.
+
+=back
=cut
sub GetMarcBiblio {
my $biblionumber = shift;
my $embeditems = shift || 0;
+ my $opac = shift || 0;
+
+ if (not defined $biblionumber) {
+ carp 'GetMarcBiblio called with undefined biblionumber';
+ return;
+ }
+
my $dbh = C4::Context->dbh;
- my $sth = $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
+ my $sth = $dbh->prepare("SELECT biblioitemnumber, marcxml FROM biblioitems WHERE biblionumber=? ");
$sth->execute($biblionumber);
my $row = $sth->fetchrow_hashref;
+ my $biblioitemnumber = $row->{'biblioitemnumber'};
my $marcxml = StripNonXmlChars( $row->{'marcxml'} );
+ my $frameworkcode = GetFrameworkCode($biblionumber);
MARC::File::XML->default_record_format( C4::Context->preference('marcflavour') );
my $record = MARC::Record->new();
if ($marcxml) {
- $record = eval { MARC::Record::new_from_xml( $marcxml, "utf8", C4::Context->preference('marcflavour') ) };
+ $record = eval {
+ MARC::Record::new_from_xml( $marcxml, "utf8",
+ C4::Context->preference('marcflavour') );
+ };
if ($@) { warn " problem with :$biblionumber : $@ \n$marcxml"; }
return unless $record;
- C4::Biblio::_koha_marc_update_bib_ids($record, '', $biblionumber, $biblionumber);
- C4::Biblio::EmbedItemsInMarcBiblio($record, $biblionumber) if ($embeditems);
+ C4::Biblio::_koha_marc_update_bib_ids( $record, $frameworkcode, $biblionumber,
+ $biblioitemnumber );
+ C4::Biblio::EmbedItemsInMarcBiblio( $record, $biblionumber, undef, $opac )
+ if ($embeditems);
return $record;
- } else {
+ }
+ else {
return;
}
}
my @listtags;
my $subfield;
- if ( $marcflavour eq "MARC21" ) {
+ if ( $marcflavour eq "MARC21" || $marcflavour eq "NORMARC" ) {
@listtags = ('345', '020');
$subfield="c";
} elsif ( $marcflavour eq "UNIMARC" ) {
( # start of capturing parenthesis
(?:
(?:[\p{Sc}\p{L}\/.]){1,4} # any character from Currency signs or Letter Unicode categories or slash or dot within 1 to 4 occurrences : call this whole block 'symbol block'
- |(?:\d+[\p{P}\s]?){1,4} # or else at least one digit followed or not by a punctuation sign or whitespace, all theese within 1 to 4 occurrences : call this whole block 'digits block'
+ |(?:\d+[\p{P}\s]?){1,4} # or else at least one digit followed or not by a punctuation sign or whitespace, all these within 1 to 4 occurrences : call this whole block 'digits block'
)
\s?\p{Sc}?\s? # followed or not by a whitespace. \p{Sc}?\s? are for cases like '25$ USD'
(?:
#---- itemtypes
if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
- return getitemtypeinfo($value)->{description};
+ return getitemtypeinfo($value)->{translated_description};
}
#---- "true" authorized value
}
my @marcissns;
foreach my $field ( $record->field($scope) ) {
- push @marcissns, $field->subfield( 'a' );
+ push @marcissns, $field->subfield( 'a' )
+ if ( $field->subfield( 'a' ) ne "" );
}
return \@marcissns;
} # end GetMarcISSN
}
# other subfields
+ my $unimarc3;
for my $authors_subfield (@subfields) {
next if ( $authors_subfield->[0] eq '9' );
+ # unimarc3 contains the $3 of the author for UNIMARC.
+ # For french academic libraries, it's the "ppn", and it's required for idref webservice
+ $unimarc3 = $authors_subfield->[1] if $marcflavour eq 'UNIMARC' and $authors_subfield->[0] =~ /3/;
+
# don't load unimarc subfields 3, 5
next if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] =~ /3|5/ ) );
push @marcauthors, {
MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop,
authoritylink => $subfield9,
+ unimarc3 => $unimarc3
};
}
return \@marcauthors;
sub TransformHtmlToXml {
my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
+ # NOTE: The parameter $ind_tag is NOT USED -- BZ 11247
+
my $xml = MARC::File::XML::header('UTF-8');
$xml .= "<record>\n";
$auth_type = C4::Context->preference('marcflavour') unless $auth_type;
@$values[$i] =~ s/"/"/g;
@$values[$i] =~ s/'/'/g;
- # if ( !utf8::is_utf8( @$values[$i] ) ) {
- # utf8::decode( @$values[$i] );
- # }
if ( ( @$tags[$i] ne $prevtag ) ) {
$j++ unless ( @$tags[$i] eq "" );
my $indicator1 = eval { substr( @$indicator[$j], 0, 1 ) };
=cut
sub TransformHtmlToMarc {
- my $cgi = shift;
+ my ($cgi, $isbiblio) = @_;
my @params = $cgi->param();
foreach my $param_name ( keys %$cgi_params ) {
if ( $param_name =~ /^tag_/ ) {
my $param_value = $cgi_params->{$param_name};
- if ( utf8::decode($param_value) ) {
- $cgi_params->{$param_name} = $param_value;
+ unless ( Encode::is_utf8( $param_value ) ) {
+ $cgi_params->{$param_name} = Encode::decode('UTF-8', $param_value );
}
-
- # FIXME - need to do something if string is not valid UTF-8
}
}
# creating a new record
my $record = MARC::Record->new();
- my $i = 0;
my @fields;
+ my ($biblionumbertagfield, $biblionumbertagsubfield) = (-1, -1);
+ ($biblionumbertagfield, $biblionumbertagsubfield) =
+ &GetMarcFromKohaField( "biblio.biblionumber", '' ) if $isbiblio;
#FIXME This code assumes that the CGI params will be in the same order as the fields in the template; this is no absolute guarantee!
- while ( $params[$i] ) { # browse all CGI params
+ for (my $i = 0; $params[$i]; $i++ ) { # browse all CGI params
my $param = $params[$i];
my $newfield = 0;
# if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
if ( $param eq 'biblionumber' ) {
- my ( $biblionumbertagfield, $biblionumbertagsubfield ) = &GetMarcFromKohaField( "biblio.biblionumber", '' );
if ( $biblionumbertagfield < 10 ) {
$newfield = MARC::Field->new( $biblionumbertagfield, $cgi->param($param), );
} else {
if ( $tag < 10 ) { # no code for theses fields
# in MARC editor, 000 contains the leader.
- if ( $tag eq '000' ) {
+ if ( $tag == $biblionumbertagfield ) {
+ # We do nothing and let $i be incremented
+ }
+ elsif ( $tag eq '000' ) {
# Force a fake leader even if not provided to avoid crashing
# during decoding MARC record containing UTF-8 characters
$record->leader(
# browse subfields for this tag (reason for _code_ match)
while(defined $params[$j] && $params[$j] =~ /_code_/) {
last unless defined $params[$j+1];
+ $j += 2 and next
+ if $tag == $biblionumbertagfield and
+ $cgi->param($params[$j]) eq $biblionumbertagsubfield;
#if next param ne subfield, then it was probably empty
#try next param by incrementing j
if($params[$j+1]!~/_subfield_/) {$j++; next; }
}
push @fields, $newfield if ($newfield);
}
- $i++;
}
$record->append_fields(@fields);
=head2 EmbedItemsInMarcBiblio
- EmbedItemsInMarcBiblio($marc, $biblionumber, $itemnumbers);
+ EmbedItemsInMarcBiblio($marc, $biblionumber, $itemnumbers, $opac);
Given a MARC::Record object containing a bib record,
modify it to include the items attached to it as 9XX
per the bib's MARC framework.
-if $itemnumbers is defined, only specified itemnumbers are embedded
+if $itemnumbers is defined, only specified itemnumbers are embedded.
+
+If $opac is true, then opac-relevant suppressions are included.
=cut
sub EmbedItemsInMarcBiblio {
- my ($marc, $biblionumber, $itemnumbers) = @_;
+ my ($marc, $biblionumber, $itemnumbers, $opac) = @_;
if ( !$marc ) {
carp 'EmbedItemsInMarcBiblio: No MARC record passed';
return;
$sth->execute($biblionumber);
my @item_fields;
my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
- while (my ($itemnumber) = $sth->fetchrow_array) {
+ my @items;
+ my $opachiddenitems = $opac
+ && ( C4::Context->preference('OpacHiddenItems') !~ /^\s*$/ );
+ require C4::Items;
+ while ( my ($itemnumber) = $sth->fetchrow_array ) {
next if @$itemnumbers and not grep { $_ == $itemnumber } @$itemnumbers;
- require C4::Items;
- my $item_marc = C4::Items::GetMarcItem($biblionumber, $itemnumber);
+ my $i = $opachiddenitems ? C4::Items::GetItem($itemnumber) : undef;
+ push @items, { itemnumber => $itemnumber, item => $i };
+ }
+ my @hiddenitems =
+ $opachiddenitems
+ ? C4::Items::GetHiddenItemnumbers( map { $_->{item} } @items )
+ : ();
+ # Convert to a hash for quick searching
+ my %hiddenitems = map { $_ => 1 } @hiddenitems;
+ foreach my $itemnumber ( map { $_->{itemnumber} } @items ) {
+ next if $hiddenitems{$itemnumber};
+ my $item_marc = C4::Items::GetMarcItem( $biblionumber, $itemnumber );
push @item_fields, $item_marc->field($itemtag);
}
$marc->append_fields(@item_fields);
=head2 CountBiblioInOrders
-=over 4
-$count = &CountBiblioInOrders( $biblionumber);
-
-=back
+ $count = &CountBiblioInOrders( $biblionumber);
This function return count of biblios in orders with $biblionumber
=head2 GetSubscriptionsId
-=over 4
-$subscriptions = &GetSubscriptionsId($biblionumber);
-
-=back
+ $subscriptions = &GetSubscriptionsId($biblionumber);
This function return an array of subscriptionid with $biblionumber
=head2 GetHolds
-=over 4
-$holds = &GetHolds($biblionumber);
-
-=back
+ $holds = &GetHolds($biblionumber);
This function return the count of holds with $biblionumber
my ($biblionumber, $increase, $value) = @_;
my $totalissues;
+ my $record = GetMarcBiblio($biblionumber);
+ unless ($record) {
+ carp "UpdateTotalIssues could not get biblio record";
+ return;
+ }
my $data = GetBiblioData($biblionumber);
+ unless ($data) {
+ carp "UpdateTotalIssues could not get datas of biblio";
+ return;
+ }
+ my ($totalissuestag, $totalissuessubfield) = GetMarcFromKohaField('biblioitems.totalissues', $data->{'frameworkcode'});
+ unless ($totalissuestag) {
+ return 1; # There is nothing to do
+ }
if (defined $value) {
$totalissues = $value;
} else {
$totalissues = $data->{'totalissues'} + $increase;
}
- my ($totalissuestag, $totalissuessubfield) = GetMarcFromKohaField('biblioitems.totalissues', $data->{'frameworkcode'});
-
- my $record = GetMarcBiblio($biblionumber);
my $field = $record->field($totalissuestag);
if (defined $field) {
$record->insert_grouped_field($field);
}
- ModBiblio($record, $biblionumber, $data->{'frameworkcode'});
- return;
+ return ModBiblio($record, $biblionumber, $data->{'frameworkcode'});
}
=head2 RemoveAllNsb