Bug 17600: Standardize our EXPORT_OK
[srvgit] / Koha / Biblio.pm
index 29c7d1e..26ee7ab 100644 (file)
@@ -19,13 +19,11 @@ package Koha::Biblio;
 
 use Modern::Perl;
 
-use Carp;
-use List::MoreUtils qw(any);
+use List::MoreUtils qw( any );
 use URI;
-use URI::Escape;
+use URI::Escape qw( uri_escape_utf8 );
 
-use C4::Koha;
-use C4::Biblio qw();
+use C4::Koha qw( GetNormalizedISBN );
 
 use Koha::Database;
 use Koha::DateUtils qw( dt_from_string );
@@ -207,35 +205,35 @@ sub can_be_transferred {
 
     my $pickup_locations = $biblio->pickup_locations( {patron => $patron } );
 
-Returns an I<arrayref> of possible pickup locations for this biblio's items,
+Returns a Koha::Libraries set of possible pickup locations for this biblio's items,
 according to patron's home library (if patron is defined and holds are allowed
 only from hold groups) and if item can be transferred to each pickup location.
 
 =cut
 
 sub pickup_locations {
-    my ($self, $params) = @_;
+    my ( $self, $params ) = @_;
 
     my $patron = $params->{patron};
 
     my @pickup_locations;
-    foreach my $item_of_bib ($self->items->as_list) {
-        push @pickup_locations, @{ $item_of_bib->pickup_locations( {patron => $patron} ) };
+    foreach my $item_of_bib ( $self->items->as_list ) {
+        push @pickup_locations,
+          $item_of_bib->pickup_locations( { patron => $patron } )
+          ->_resultset->get_column('branchcode')->all;
     }
 
-    my %seen;
-    @pickup_locations =
-      grep { !$seen{ $_->branchcode }++ } @pickup_locations;
-
-    return \@pickup_locations;
+    return Koha::Libraries->search(
+        { branchcode => { '-in' => \@pickup_locations } }, { order_by => ['branchname'] } );
 }
 
 =head3 hidden_in_opac
 
-my $bool = $biblio->hidden_in_opac({ [ rules => $rules ] })
+    my $bool = $biblio->hidden_in_opac({ [ rules => $rules ] })
 
 Returns true if the biblio matches the hidding criteria defined in $rules.
-Returns false otherwise.
+Returns false otherwise. It involves the I<OpacHiddenItems> and
+I<OpacHiddenItemsHidesRecord> system preferences.
 
 Takes HASHref that can have the following parameters:
     OPTIONAL PARAMETERS:
@@ -255,6 +253,9 @@ sub hidden_in_opac {
 
     return 0 unless @items; # Do not hide if there is no item
 
+    # Ok, there are items, don't even try the rules unless OpacHiddenItemsHidesRecord
+    return 0 unless C4::Context->preference('OpacHiddenItemsHidesRecord');
+
     return !(any { !$_->hidden_in_opac({ rules => $rules }) } @items);
 }
 
@@ -757,14 +758,17 @@ sub custom_cover_image_url {
     my $url = C4::Context->preference('CustomCoverImagesURL');
     if ( $url =~ m|{isbn}| ) {
         my $isbn = $self->biblioitem->isbn;
+        return unless $isbn;
         $url =~ s|{isbn}|$isbn|g;
     }
     if ( $url =~ m|{normalized_isbn}| ) {
         my $normalized_isbn = C4::Koha::GetNormalizedISBN($self->biblioitem->isbn);
+        return unless $normalized_isbn;
         $url =~ s|{normalized_isbn}|$normalized_isbn|g;
     }
     if ( $url =~ m|{issn}| ) {
         my $issn = $self->biblioitem->issn;
+        return unless $issn;
         $url =~ s|{issn}|$issn|g;
     }
 
@@ -774,6 +778,7 @@ sub custom_cover_image_url {
         my $subfield = $+{subfield};
         my $marc_record = $self->metadata->record;
         my $value = $marc_record->subfield($field, $subfield);
+        return unless $value;
         $url =~ s|$re|$value|;
     }
 
@@ -794,6 +799,58 @@ sub cover_images {
     return Koha::CoverImages->_new_from_dbic($cover_images_rs);
 }
 
+=head3 get_marc_notes
+
+    $marcnotesarray = $biblio->get_marc_notes({ marcflavour => $marcflavour });
+
+Get all notes from the MARC record and returns them in an array.
+The notes are stored in different fields depending on MARC flavour.
+MARC21 5XX $u subfields receive special attention as they are URIs.
+
+=cut
+
+sub get_marc_notes {
+    my ( $self, $params ) = @_;
+
+    my $marcflavour = $params->{marcflavour};
+    my $opac = $params->{opac};
+
+    my $scope = $marcflavour eq "UNIMARC"? '3..': '5..';
+    my @marcnotes;
+
+    #MARC21 specs indicate some notes should be private if first indicator 0
+    my %maybe_private = (
+        541 => 1,
+        542 => 1,
+        561 => 1,
+        583 => 1,
+        590 => 1
+    );
+
+    my %hiddenlist = map { $_ => 1 }
+        split( /,/, C4::Context->preference('NotesToHide'));
+    foreach my $field ( $self->metadata->record->field($scope) ) {
+        my $tag = $field->tag();
+        next if $hiddenlist{ $tag };
+        next if $opac && $maybe_private{$tag} && !$field->indicator(1);
+        if( $marcflavour ne 'UNIMARC' && $field->subfield('u') ) {
+            # Field 5XX$u always contains URI
+            # Examples: 505u, 506u, 510u, 514u, 520u, 530u, 538u, 540u, 542u, 552u, 555u, 561u, 563u, 583u
+            # We first push the other subfields, then all $u's separately
+            # Leave further actions to the template (see e.g. opac-detail)
+            my $othersub =
+                join '', ( 'a' .. 't', 'v' .. 'z', '0' .. '9' ); # excl 'u'
+            push @marcnotes, { marcnote => $field->as_string($othersub) };
+            foreach my $sub ( $field->subfield('u') ) {
+                $sub =~ s/^\s+|\s+$//g; # trim
+                push @marcnotes, { marcnote => $sub };
+            }
+        } else {
+            push @marcnotes, { marcnote => $field->as_string() };
+        }
+    }
+    return \@marcnotes;
+}
 
 =head3 to_api
 
@@ -832,6 +889,69 @@ sub to_api_mapping {
     };
 }
 
+=head3 get_marc_host
+
+    $host = $biblio->get_marc_host;
+    # OR:
+    ( $host, $relatedparts ) = $biblio->get_marc_host;
+
+    Returns host biblio record from MARC21 773 (undef if no 773 present).
+    It looks at the first 773 field with MARCorgCode or only a control
+    number. Complete $w or numeric part is used to search host record.
+    The optional parameter no_items triggers a check if $biblio has items.
+    If there are, the sub returns undef.
+    Called in list context, it also returns 773$g (related parts).
+
+=cut
+
+sub get_marc_host {
+    my ($self, $params) = @_;
+    my $no_items = $params->{no_items};
+    return if C4::Context->preference('marcflavour') eq 'UNIMARC'; # TODO
+    return if $params->{no_items} && $self->items->count > 0;
+
+    my $record;
+    eval { $record = $self->metadata->record };
+    return if !$record;
+
+    # We pick the first $w with your MARCOrgCode or the first $w that has no
+    # code (between parentheses) at all.
+    my $orgcode = C4::Context->preference('MARCOrgCode') // q{};
+    my $hostfld;
+    foreach my $f ( $record->field('773') ) {
+        my $w = $f->subfield('w') or next;
+        if( $w =~ /^\($orgcode\)\s*(\d+)/i or $w =~ /^\d+/ ) {
+            $hostfld = $f;
+            last;
+        }
+    }
+    return if !$hostfld;
+    my $rcn = $hostfld->subfield('w');
+
+    # Look for control number with/without orgcode
+    my $engine = Koha::SearchEngine::Search->new({ index => $Koha::SearchEngine::BIBLIOS_INDEX });
+    my $bibno;
+    for my $try (1..2) {
+        my ( $error, $results, $total_hits ) = $engine->simple_search_compat( 'Control-number='.$rcn, 0,1 );
+        if( !$error and $total_hits == 1 ) {
+            $bibno = $engine->extract_biblionumber( $results->[0] );
+            last;
+        }
+        # Add or remove orgcode for second try
+        if( $try == 1 && $rcn =~ /\)\s*(\d+)/ ) {
+            $rcn = $1; # number only
+        } elsif( $try == 1 && $rcn =~ /^\d+/ ) {
+            $rcn = "($orgcode)$rcn";
+        } else {
+            last;
+        }
+    }
+    if( $bibno ) {
+        my $host = Koha::Biblios->find($bibno) or return;
+        return wantarray ? ( $host, $hostfld->subfield('g') ) : $host;
+    }
+}
+
 =head2 Internal methods
 
 =head3 type