ffzg/recall_notices.pl: added --interval and --dedup
[koha.git] / catalogue / search.pl
index 9f75221..f3d653f 100755 (executable)
@@ -94,7 +94,7 @@ weighting, koha-specific relevance ranking, and stemming. When I have a chance
 I'll try to flesh out this section to better explain.
 
 This query incorporates query profiles that aren't compatible with most non-Zebra 
-Z39.50 targets to acomplish the field weighting and relevance ranking.
+Z39.50 targets to accomplish the field weighting and relevance ranking.
 
 =item 2 $simple_query - a simple query that doesn't contain the field weighting,
 stemming, etc., suitable to pass off to other search targets
@@ -132,8 +132,7 @@ Not yet completed...
 
 =cut
 
-use strict;            # always use
-#use warnings; FIXME - Bug 2505
+use Modern::Perl;
 
 ## STEP 1. Load things that are used in both search page and
 # results page and decide which template to load, operations 
@@ -151,11 +150,12 @@ use POSIX qw(ceil floor);
 use C4::Search::History;
 
 use Koha::ItemTypes;
-use Koha::LibraryCategories;
+use Koha::Library::Groups;
 use Koha::Patrons;
 use Koha::SearchEngine::Search;
 use Koha::SearchEngine::QueryBuilder;
 use Koha::Virtualshelves;
+use Koha::SearchFields;
 
 use URI::Escape;
 
@@ -171,6 +171,7 @@ my $template_type;
 my @params = $cgi->multi_param("limit");
 if ((@params>=1) || ($cgi->param("q")) || ($cgi->param('multibranchlimit')) || ($cgi->param('limit-yr')) ) {
     $template_name = 'catalogue/results.tt';
+    $template_type = 'results';
 }
 else {
     $template_name = 'catalogue/advsearch.tt';
@@ -210,12 +211,13 @@ if($cgi->cookie("intranet_bib_list")){
     @cart_list = split(/\//, $cart_list);
 }
 
-# load the branches
-my $categories = Koha::LibraryCategories->search( { categorytype => 'searchdomain' }, { order_by => [ 'categorytype', 'categorycode' ] } );
+my @search_groups =
+  Koha::Library::Groups->get_search_groups( { interface => 'staff' } );
+@search_groups = sort { $a->title cmp $b->title } @search_groups;
 
 $template->param(
     selected_branchcode => ( C4::Context->IsSuperLibrarian ? C4::Context->userenv : '' ),
-    searchdomainloop => $categories
+    search_groups    => \@search_groups,
 );
 
 # load the Type stuff
@@ -292,7 +294,7 @@ if ( $template_type eq 'advsearch' ) {
     # shouldn't appear on the first one, scan indexes should, adding a new
     # box should only appear on the last, etc.
     my @search_boxes_array;
-    my $search_boxes_count = 3; # begin whith 3 boxes
+    my $search_boxes_count = 3; # begin with 3 boxes
     # FIXME: all this junk can be done in TMPL using __first__ and __last__
     for (my $i=1;$i<=$search_boxes_count;$i++) {
         # if it's the first one, don't display boolean option, but show scan indexes
@@ -382,13 +384,21 @@ my @indexes = map uri_unescape($_), $cgi->multi_param('idx');
 # if a simple index (only one)  display the index used in the top search box
 if ($indexes[0] && (!$indexes[1] || $params->{'scan'})) {
     my $idx = "ms_".$indexes[0];
-    $idx =~ s/\,/comma/g;  # template toolkit doesnt like variables with a , in it
+    $idx =~ s/\,/comma/g;  # template toolkit doesn't like variables with a , in it
+    $idx =~ s/-/dash/g;  # template toolkit doesn't like variables with a dash in it
     $template->param($idx => 1);
 }
 
 # an operand can be a single term, a phrase, or a complete ccl query
 my @operands = map uri_unescape($_), $cgi->multi_param('q');
 
+# if a simple search, display the value in the search box
+if ($operands[0] && !$operands[1]) {
+    my $ms_query = $operands[0];
+    $ms_query =~ s/ #\S+//;
+    $template->param(ms_value => $ms_query);
+}
+
 # limits are use to limit to results to a pre-defined category such as branch or language
 my @limits = map uri_unescape($_), $cgi->multi_param('limit');
 my @nolimits = map uri_unescape($_), $cgi->multi_param('nolimit');
@@ -396,9 +406,9 @@ my %is_nolimit = map { $_ => 1 } @nolimits;
 @limits = grep { not $is_nolimit{$_} } @limits;
 
 if($params->{'multibranchlimit'}) {
-    my $library_category = Koha::LibraryCategories->find( $params->{multibranchlimit} );
-    my @libraries = $library_category->libraries;
-    my $multibranch = '('.join( " or ", map { 'branch: ' . $_->id } @libraries ) .')';
+    my $search_group = Koha::Library::Groups->find( $params->{multibranchlimit} );
+    my @libraries = $search_group->all_libraries;
+    my $multibranch = '('.join( " or ", map { 'branch: ' . $_->branchcode } @libraries ) .')';
     push @limits, $multibranch if ($multibranch ne  '()');
 }
 
@@ -449,12 +459,16 @@ my $offset = $params->{'offset'} || 0;
 $offset = 0 if $offset < 0;
 my $page = $cgi->param('page') || 1;
 #my $offset = ($page-1)*$results_per_page;
-my $hits;
 my $expanded_facet = $params->{'expand'};
 
 # Define some global variables
 my ( $error,$query,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$query_type);
 
+my $build_params;
+unless ( $cgi->param('advsearch') ) {
+    $build_params->{weighted_fields} = 1;
+}
+
 my $builder = Koha::SearchEngine::QueryBuilder->new(
     { index => $Koha::SearchEngine::BIBLIOS_INDEX } );
 my $searcher = Koha::SearchEngine::Search->new(
@@ -467,49 +481,54 @@ my $searcher = Koha::SearchEngine::Search->new(
     $query_type
   )
   = $builder->build_query_compat( \@operators, \@operands, \@indexes, \@limits,
-    \@sort_by, $scan, $lang );
+    \@sort_by, $scan, $lang, $build_params );
 
 ## parse the query_cgi string and put it into a form suitable for <input>s
 my @query_inputs;
 my $scan_index_to_use;
 my $scan_search_term_to_use;
 
-for my $this_cgi ( split('&',$query_cgi) ) {
-    next unless $this_cgi;
-    $this_cgi =~ m/(.*?)=(.*)/;
-    my $input_name = $1;
-    my $input_value = $2;
-    push @query_inputs, { input_name => $input_name, input_value => Encode::decode_utf8( uri_unescape( $input_value ) ) };
-    if ($input_name eq 'idx') {
-        $scan_index_to_use = $input_value; # unless $scan_index_to_use;
-    }
-    if ($input_name eq 'q') {
-        $scan_search_term_to_use = Encode::decode_utf8( uri_unescape( $input_value ));
+if ($query_cgi) {
+    for my $this_cgi ( split('&', $query_cgi) ) {
+        next unless $this_cgi;
+        $this_cgi =~ m/(.*?)=(.*)/;
+        my $input_name = $1;
+        my $input_value = $2;
+        push @query_inputs, { input_name => $input_name, input_value => Encode::decode_utf8( uri_unescape( $input_value ) ) };
+        if ($input_name eq 'idx') {
+            $scan_index_to_use = $input_value; # unless $scan_index_to_use;
+        }
+        if ($input_name eq 'q') {
+            $scan_search_term_to_use = Encode::decode_utf8( uri_unescape( $input_value ));
+        }
     }
 }
+
 $template->param ( QUERY_INPUTS => \@query_inputs,
                    scan_index_to_use => $scan_index_to_use,
                    scan_search_term_to_use => $scan_search_term_to_use );
 
 ## parse the limit_cgi string and put it into a form suitable for <input>s
 my @limit_inputs;
-for my $this_cgi ( split('&',$limit_cgi) ) {
-    next unless $this_cgi;
-    # handle special case limit-yr
-    if ($this_cgi =~ /yr,st-numeric/) {
-        push @limit_inputs, { input_name => 'limit-yr', input_value => $limit_yr_value };   
-        next;
+if ($limit_cgi) {
+    for my $this_cgi ( split('&', $limit_cgi) ) {
+        next unless $this_cgi;
+        # handle special case limit-yr
+        if ($this_cgi =~ /yr,st-numeric/) {
+            push @limit_inputs, { input_name => 'limit-yr', input_value => $limit_yr_value };
+            next;
+        }
+        $this_cgi =~ m/(.*=)(.*)/;
+        my $input_name = $1;
+        my $input_value = $2;
+        $input_name =~ s/=$//;
+        push @limit_inputs, { input_name => $input_name, input_value => Encode::decode_utf8( uri_unescape($input_value) ) };
     }
-    $this_cgi =~ m/(.*=)(.*)/;
-    my $input_name = $1;
-    my $input_value = $2;
-    $input_name =~ s/=$//;
-    push @limit_inputs, { input_name => $input_name, input_value => Encode::decode_utf8( uri_unescape($input_value) ) };
 }
 $template->param ( LIMIT_INPUTS => \@limit_inputs );
 
 ## II. DO THE SEARCH AND GET THE RESULTS
-my $total; # the total results for the whole set
+my $total = 0; # the total results for the whole set
 my $facets; # this object stores the faceted results that display on the left-hand of the results page
 my $results_hashref;
 
@@ -534,11 +553,11 @@ my @sup_results_array;
 for (my $i=0;$i<@servers;$i++) {
     my $server = $servers[$i];
     if ($server =~/biblioserver/) { # this is the local bibliographic server
-        $hits = $results_hashref->{$server}->{"hits"};
+        my $hits = $results_hashref->{$server}->{"hits"} // 0;
         my $page = $cgi->param('page') || 0;
-        my @newresults = searchResults('intranet', $query_desc, $hits, $results_per_page, $offset, $scan,
+        my @newresults = searchResults({ 'interface' => 'intranet' }, $query_desc, $hits, $results_per_page, $offset, $scan,
                                        $results_hashref->{$server}->{"RECORDS"});
-        $total = $total + $results_hashref->{$server}->{"hits"};
+        $total = $total + $hits;
 
         # Search history
         if (C4::Context->preference('EnableSearchHistory')) {
@@ -586,9 +605,11 @@ for (my $i=0;$i<@servers;$i++) {
 
         if ($hits) {
             $template->param(total => $hits);
-            my $limit_cgi_not_availablity = $limit_cgi;
-            $limit_cgi_not_availablity =~ s/&limit=available//g;
-            $template->param(limit_cgi_not_availablity => $limit_cgi_not_availablity);
+            if ($limit_cgi) {
+                my $limit_cgi_not_availablity = $limit_cgi;
+                $limit_cgi_not_availablity =~ s/&limit=available//g;
+                $template->param(limit_cgi_not_availablity => $limit_cgi_not_availablity);
+            }
             $template->param(limit_cgi => $limit_cgi);
             $template->param(query_cgi => $query_cgi);
             $template->param(query_desc => $query_desc);
@@ -612,8 +633,11 @@ for (my $i=0;$i<@servers;$i++) {
             ## FIXME: add a global function for this, it's better than the current global one
             ## Build the page numbers on the bottom of the page
             my @page_numbers;
+            my $max_result_window = $searcher->max_result_window;
+            my $hits_to_paginate = ($max_result_window && $max_result_window < $hits) ? $max_result_window : $hits;
+            $template->param( hits_to_paginate => $hits_to_paginate );
             # total number of pages there will be
-            my $pages = ceil($hits / $results_per_page);
+            my $pages = ceil($hits_to_paginate / $results_per_page);
             my $last_page_offset = ( $pages -1 ) * $results_per_page;
             # default page number
             my $current_page_number = 1;
@@ -703,13 +727,13 @@ for (my $i=0;$i<@servers;$i++) {
 $template->{'VARS'}->{'searchid'} = $cgi->param('searchid');
 
 my $gotonumber = $cgi->param('gotoNumber');
-if ($gotonumber eq 'last' || $gotonumber eq 'first') {
+if ( $gotonumber && ( $gotonumber eq 'last' || $gotonumber eq 'first' ) ) {
     $template->{'VARS'}->{'gotoNumber'} = $gotonumber;
 }
 $template->{'VARS'}->{'gotoPage'}   = 'detail.pl';
 my $gotopage = $cgi->param('gotoPage');
 $template->{'VARS'}->{'gotoPage'} = $gotopage
-  if $gotopage =~ m/^(ISBD|labeledMARC|MARC|more)?detail.pl$/;
+  if $gotopage && $gotopage =~ m/^(ISBD|labeledMARC|MARC|more)?detail.pl$/;
 
 for my $facet ( @$facets ) {
     for my $entry ( @{ $facet->{facets} } ) {