Bug 18215: Fix another tls warning
[koha.git] / C4 / Matcher.pm
index c0634ec..40e6e5f 100644 (file)
@@ -4,31 +4,26 @@ package C4::Matcher;
 #
 # 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 Modern::Perl;
 
-use C4::Context;
 use MARC::Record;
 
-use vars qw($VERSION);
-
-BEGIN {
-       # set the version for version checking
-    $VERSION = 3.07.00.049;
-}
+use Koha::SearchEngine;
+use Koha::SearchEngine::Search;
+use Koha::Util::Normalize qw/legacy_default remove_spaces upper_case lower_case/;
 
 =head1 NAME
 
@@ -626,20 +621,50 @@ sub get_matches {
 
     my %matches = ();
 
-    foreach my $matchpoint (@{ $self->{'matchpoints'} }) {
-        my @source_keys = _get_match_keys($source_record, $matchpoint);
+    my $QParser;
+    $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser'));
+    foreach my $matchpoint ( @{ $self->{'matchpoints'} } ) {
+        my @source_keys = _get_match_keys( $source_record, $matchpoint );
+
         next if scalar(@source_keys) == 0;
+
+        # FIXME - because of a bug in QueryParser, an expression ofthe
+        # format 'isbn:"isbn1" || isbn:"isbn2" || isbn"isbn3"...'
+        # does not get parsed correctly, so we will not
+        # do AggressiveMatchOnISBN if UseQueryParser is on
+        @source_keys = C4::Koha::GetVariationsOfISBNs(@source_keys)
+          if ( $matchpoint->{index} =~ /^isbn$/i
+            && C4::Context->preference('AggressiveMatchOnISBN') )
+            && !C4::Context->preference('UseQueryParser');
+
+        @source_keys = C4::Koha::GetVariationsOfISSNs(@source_keys)
+          if ( $matchpoint->{index} =~ /^issn$/i
+            && C4::Context->preference('AggressiveMatchOnISSN') )
+            && !C4::Context->preference('UseQueryParser');
+
         # build query
         my $query;
         my $error;
         my $searchresults;
         my $total_hits;
-        if ($self->{'record_type'} eq 'biblio') {
-            $query = join(" or ", map { "$matchpoint->{'index'}=$_" } @source_keys);
-# FIXME only searching biblio index at the moment
-            require C4::Search;
-            ($error, $searchresults, $total_hits) = C4::Search::SimpleSearch($query, 0, $max_matches);
-        } elsif ($self->{'record_type'} eq 'authority') {
+        if ( $self->{'record_type'} eq 'biblio' ) {
+
+            if ($QParser) {
+                $query = join( " || ",
+                    map { "$matchpoint->{'index'}:$_" } @source_keys );
+            }
+            else {
+                my $phr = ( C4::Context->preference('AggressiveMatchOnISBN') || C4::Context->preference('AggressiveMatchOnISSN') )  ? ',phr' : q{};
+                $query = join( " or ",
+                    map { "$matchpoint->{'index'}$phr=\"$_\"" } @source_keys );
+                    #NOTE: double-quote the values so you don't get a "Embedded truncation not supported" error when a term has a ? in it.
+            }
+
+            my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
+            ( $error, $searchresults, $total_hits ) =
+              $searcher->simple_search_compat( $query, 0, $max_matches );
+        }
+        elsif ( $self->{'record_type'} eq 'authority' ) {
             my $authresults;
             my @marclist;
             my @and_or;
@@ -648,24 +673,27 @@ sub get_matches {
             my @value;
             foreach my $key (@source_keys) {
                 push @marclist, $matchpoint->{'index'};
-                push @and_or, 'or';
+                push @and_or,   'or';
                 push @operator, 'exact';
-                push @value, $key;
+                push @value,    $key;
             }
             require C4::AuthoritiesMarc;
-            ($authresults, $total_hits) = C4::AuthoritiesMarc::SearchAuthorities(
-                    \@marclist, \@and_or, \@excluding, \@operator,
-                    \@value, 0, 20, undef, 'AuthidAsc', 1
-            );
+            ( $authresults, $total_hits ) =
+              C4::AuthoritiesMarc::SearchAuthorities(
+                \@marclist,  \@and_or, \@excluding, \@operator,
+                \@value,     0,        20,          undef,
+                'AuthidAsc', 1
+              );
             foreach my $result (@$authresults) {
                 push @$searchresults, $result->{'authid'};
             }
         }
 
-        if (defined $error ) {
+        if ( defined $error ) {
             warn "search failed ($query) $error";
-        } else {
-            foreach my $matched (@{$searchresults}) {
+        }
+        else {
+            foreach my $matched ( @{$searchresults} ) {
                 $matches{$matched} += $matchpoint->{'score'};
             }
         }
@@ -682,9 +710,9 @@ sub get_matches {
     if ($self->{'record_type'} eq 'biblio') {
         require C4::Biblio;
         foreach my $marcblob (keys %matches) {
-            my $target_record = MARC::Record->new_from_usmarc($marcblob);
+            my $target_record = C4::Search::new_record_from_zebra('biblioserver',$marcblob);
             my $record_number;
-            my $result = C4::Biblio::TransformMarcToKoha(C4::Context->dbh, $target_record, '');
+            my $result = C4::Biblio::TransformMarcToKoha($target_record, '');
             $record_number = $result->{'biblionumber'};
             push @results, { 'record_id' => $record_number, 'score' => $matches{$marcblob} };
         }
@@ -750,6 +778,7 @@ sub _passes_required_checks {
 }
 
 sub _get_match_keys {
+
     my $source_record = shift;
     my $matchpoint = shift;
     my $check_only_first_repeat = @_ ? shift : 0;
@@ -768,7 +797,7 @@ sub _get_match_keys {
     # If there are two 003s and two 001s, there will be two keys:
     #    first 003 + first 001
     #    second 003 + second 001
-    
+
     my @keys = ();
     for (my $i = 0; $i <= $#{ $matchpoint->{'components'} }; $i++) {
         my $component = $matchpoint->{'components'}->[$i];
@@ -777,24 +806,45 @@ sub _get_match_keys {
             $j++;
             last FIELD if $j > 0 and $check_only_first_repeat;
             last FIELD if $i > 0 and $j > $#keys;
-            my $key = "";
-                       my $string;
-            if ($field->is_control_field()) {
-                               $string=$field->data();
+
+            my $string;
+            if ( $field->is_control_field() ) {
+                $string = $field->data();
             } else {
-                foreach my $subfield ($field->subfields()) {
-                    if (exists $component->{'subfields'}->{$subfield->[0]}) {
-                        $string .= " " . $subfield->[1];
-                    }
-                }
-                       }
+                $string = $field->as_string(
+                    join('', keys %{ $component->{ subfields } }), ' ' # ' ' as separator
+                );
+            }
+
             if ($component->{'length'}>0) {
-                    $string= substr($string, $component->{'offset'}, $component->{'length'});
-                            # FIXME normalize, substr
+                $string= substr($string, $component->{'offset'}, $component->{'length'});
             } elsif ($component->{'offset'}) {
-                    $string= substr($string, $component->{'offset'});
+                $string= substr($string, $component->{'offset'});
+            }
+
+            my $norms = $component->{'norms'};
+            my $key = $string;
+
+            foreach my $norm ( @{ $norms } ) {
+                if ( grep { $norm eq $_ } valid_normalization_routines() ) {
+                    if ( $norm eq 'remove_spaces' ) {
+                        $key = remove_spaces($key);
+                    }
+                    elsif ( $norm eq 'upper_case' ) {
+                        $key = upper_case($key);
+                    }
+                    elsif ( $norm eq 'lower_case' ) {
+                        $key = lower_case($key);
+                    }
+                    elsif ( $norm eq 'legacy_default' ) {
+                        $key = legacy_default($key);
+                    }
+                } else {
+                    warn "Invalid normalization routine required ($norm)"
+                        unless $norm eq 'none';
+                }
             }
-            $key = _normalize($string);
+
             if ($i == 0) {
                 push @keys, $key if $key;
             } else {
@@ -819,16 +869,14 @@ sub _parse_match_component {
     return $component;
 }
 
-# FIXME - default normalizer
-sub _normalize {
-    my $value = uc shift;
-    $value =~ s/[.;:,\]\[\)\(\/'"]//g;
-    $value =~ s/^\s+//;
-    #$value =~ s/^\s+$//;
-    $value =~ s/\s+$//;
-    $value =~ s/\s+/ /g;
-    #$value =~ s/[.;,\]\[\)\(\/"']//g;
-    return $value;
+sub valid_normalization_routines {
+
+    return (
+        'remove_spaces',
+        'upper_case',
+        'lower_case',
+        'legacy_default'
+    );
 }
 
 1;