X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;ds=inline;f=catalogue%2Fsearch.pl;h=acd9f4cc3efa75851a0effce001597d0469dfd77;hb=0cf2eccfe926f77753a2b948e2babf077e2975d3;hp=b6c09134ccd5862bd7a6ccc9ac94c5b59bc0284d;hpb=67ffed7fec7f3b3a0db60e6f71060d5b43f03e94;p=koha_fer diff --git a/catalogue/search.pl b/catalogue/search.pl index b6c09134cc..acd9f4cc3e 100755 --- a/catalogue/search.pl +++ b/catalogue/search.pl @@ -2,9 +2,8 @@ # Script to perform searching # For documentation try 'perldoc /path/to/search' # -# $Header$ -# # Copyright 2006 LibLime +# Copyright 2010 BibLibre # # This file is part of Koha # @@ -17,9 +16,9 @@ # 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., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA +# 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. =head1 NAME @@ -81,7 +80,7 @@ There are several additional secondary functions performed that I will not cover in detail. =head3 1. Building Query Strings - + There are several types of queries needed in the process of search and retrieve: =over @@ -134,6 +133,7 @@ Not yet completed... =cut use strict; # always use +#use warnings; FIXME - Bug 2505 ## STEP 1. Load things that are used in both search page and # results page and decide which template to load, operations @@ -142,13 +142,16 @@ use strict; # always use ## load Koha modules use C4::Context; use C4::Output; -use C4::Auth; +use C4::Auth qw(:DEFAULT get_session); use C4::Search; use C4::Languages qw(getAllLanguages); use C4::Koha; +use C4::Members qw(GetMember); +use C4::VirtualShelves qw(GetRecentShelves); use POSIX qw(ceil floor); use C4::Branch; # GetBranches +my $DisplayMultiPlaceHold = C4::Context->preference("DisplayMultiPlaceHold"); # create a new CGI object # FIXME: no_undef_params needs to be tested use CGI qw('-no_undef_params'); @@ -180,6 +183,16 @@ if (C4::Context->preference("marcflavour") eq "UNIMARC" ) { $template->param('UNIMARC' => 1); } +if($cgi->cookie("holdfor")){ + my $holdfor_patron = GetMember('borrowernumber' => $cgi->cookie("holdfor")); + $template->param( + holdfor => $cgi->cookie("holdfor"), + holdfor_surname => $holdfor_patron->{'surname'}, + holdfor_firstname => $holdfor_patron->{'firstname'}, + holdfor_cardnumber => $holdfor_patron->{'cardnumber'}, + ); +} + ## URI Re-Writing # Deprecated, but preserved because it's interesting :-) # The same thing can be accomplished with mod_rewrite in @@ -206,38 +219,64 @@ if (C4::Context->preference("marcflavour") eq "UNIMARC" ) { # load the branches my $branches = GetBranches(); -my @branch_loop; -for my $branch_hash (sort keys %$branches) { - push @branch_loop, {value => "$branch_hash" , branchname => $branches->{$branch_hash}->{'branchname'}, }; -} +# Populate branch_loop with all branches sorted by their name. If +# independantbranches is activated, set the default branch to the borrower +# branch, except for superlibrarian who need to search all libraries. +my $user = C4::Context->userenv; +my @branch_loop = map { + { + value => $_, + branchname => $branches->{$_}->{branchname}, + selected => $user->{branch} eq $_ && C4::Branch::onlymine(), + } +} sort { + $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} +} keys %$branches; my $categories = GetBranchCategories(undef,'searchdomain'); $template->param(branchloop => \@branch_loop, searchdomainloop => $categories); -# load the itemtypes +# load the Type stuff +# load the Type stuff my $itemtypes = GetItemTypes; +# the index parameter is different for item-level itemtypes +my $itype_or_itemtype = (C4::Context->preference("item-level_itypes"))?'itype':'itemtype'; my @itemtypesloop; my $selected=1; my $cnt; -my $imgdir = getitemtypeimagesrc('intranet'); -foreach my $thisitemtype ( sort {$itemtypes->{$a}->{'description'} cmp $itemtypes->{$b}->{'description'} } keys %$itemtypes ) { +my $advanced_search_types = C4::Context->preference("AdvancedSearchTypes"); + +if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') { foreach my $thisitemtype ( sort {$itemtypes->{$a}->{'description'} cmp $itemtypes->{$b}->{'description'} } keys %$itemtypes ) { my %row =( number=>$cnt++, - imageurl=> $itemtypes->{$thisitemtype}->{'imageurl'}?($imgdir."/".$itemtypes->{$thisitemtype}->{'imageurl'}):"", + ccl => qq($itype_or_itemtype,phr), code => $thisitemtype, selected => $selected, description => $itemtypes->{$thisitemtype}->{'description'}, count5 => $cnt % 4, + imageurl=> getitemtypeimagelocation( 'intranet', $itemtypes->{$thisitemtype}->{'imageurl'} ), ); - $selected = 0 if ($selected) ; - push @itemtypesloop, \%row; + $selected = 0 if ($selected) ; + push @itemtypesloop, \%row; + } + $template->param(itemtypeloop => \@itemtypesloop); +} else { + my $advsearchtypes = GetAuthorisedValues($advanced_search_types); + for my $thisitemtype (sort {$a->{'lib'} cmp $b->{'lib'}} @$advsearchtypes) { + my %row =( + number=>$cnt++, + ccl => $advanced_search_types, + code => $thisitemtype->{authorised_value}, + selected => $selected, + description => $thisitemtype->{'lib'}, + count5 => $cnt % 4, + imageurl=> getitemtypeimagelocation( 'intranet', $thisitemtype->{'imageurl'} ), + ); + push @itemtypesloop, \%row; + } + $template->param(itemtypeloop => \@itemtypesloop); } -$template->param(itemtypeloop => \@itemtypesloop); - -# load the ccodes -# my ($ccodecount,@ccode_loop) = GetCcodes(); -# $template->param(ccodeloop=>\@ccode_loop,); # The following should only be loaded if we're bringing up the advanced search template if ( $template_type eq 'advsearch' ) { @@ -246,22 +285,24 @@ if ( $template_type eq 'advsearch' ) { my $primary_servers_loop;# = displayPrimaryServers(); $template->param(outer_servers_loop => $primary_servers_loop,); - my $secondary_servers_loop;# = displaySecondaryServers(); + my $secondary_servers_loop; $template->param(outer_sup_servers_loop => $secondary_servers_loop,); - + + # set the default sorting + my $default_sort_by = C4::Context->preference('defaultSortField')."_".C4::Context->preference('defaultSortOrder') + if (C4::Context->preference('OPACdefaultSortField') && C4::Context->preference('OPACdefaultSortOrder')); + $template->param($default_sort_by => 1); + # determine what to display next to the search boxes (ie, boolean option # 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 = C4::Context->preference("OPACAdvSearchInputCount") | 3; # FIXME: should be a syspref + my $search_boxes_count = C4::Context->preference("OPACAdvSearchInputCount") || 3; # FIXME: using OPAC sysprefs? + # 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 if ($i==1) { - push @search_boxes_array, - { - scan_index => 1, - }; - + push @search_boxes_array, {scan_index => 1}; } # if it's the last one, show the 'add field' box elsif ($i==$search_boxes_count) { @@ -295,6 +336,8 @@ if ( $template_type eq 'advsearch' ) { $template->param( expanded_options => $cgi->param('expanded_options')); } + $template->param(virtualshelves => C4::Context->preference("virtualshelves")); + output_html_with_http_headers $cgi, $cookie, $template->output; exit; } @@ -339,6 +382,11 @@ my @operators; my @indexes; @indexes = split("\0",$params->{'idx'}); +# if a simple index (only one) display the index used in the top search box +if ($indexes[0] && (!$indexes[1] || $params->{'scan'})) { + $template->param("ms_".$indexes[0] => 1);} + + # an operand can be a single term, a phrase, or a complete ccl query my @operands; @operands = split("\0",$params->{'q'}) if $params->{'q'}; @@ -348,7 +396,7 @@ my @limits; @limits = split("\0",$params->{'limit'}) if $params->{'limit'}; if($params->{'multibranchlimit'}) { -push @limits, join(" or ", map { "branch: $_ "} @{GetBranchesInCategory($params->{'multibranchlimit'})}) ; + push @limits, '('.join( " or ", map { "branch: $_ " } @{ GetBranchesInCategory( $params->{'multibranchlimit'} ) } ).')'; } my $available; @@ -376,6 +424,25 @@ if ($params->{'limit-yr'}) { #FIXME: Should return a error to the user, incorect date format specified } +# convert indexes and operands to corresponding parameter names for the z3950 search +# $ %z3950p will be a hash ref if the indexes are present (advacned search), otherwise undef +my $z3950par; +my $indexes2z3950 = { + kw=>'title', au=>'author', 'au,phr'=>'author', nb=>'isbn', ns=>'issn', + 'lcn,phr'=>'dewey', su=>'subject', 'su,phr'=>'subject', + ti=>'title', 'ti,phr'=>'title', se=>'title' +}; +for (my $ii = 0; $ii < @operands; ++$ii) +{ + my $name = $indexes2z3950->{$indexes[$ii]}; + if (defined $name && defined $operands[$ii]) + { + $z3950par ||= {}; + $z3950par->{$name} = $operands[$ii] if !exists $z3950par->{$name}; + } +} + + # Params that can only have one value my $scan = $params->{'scan'}; my $count = C4::Context->preference('numSearchResults') || 20; @@ -392,19 +459,25 @@ my ( $error,$query,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit my @results; ## I. BUILD THE QUERY -( $error,$query,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$stopwords_removed,$query_type) = buildQuery(\@operators,\@operands,\@indexes,\@limits,\@sort_by,$scan); +my $lang = C4::Output::getlanguagecookie($cgi); +( $error,$query,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$stopwords_removed,$query_type) = buildQuery(\@operators,\@operands,\@indexes,\@limits,\@sort_by,$scan,$lang); ## parse the query_cgi string and put it into a form suitable for s my @query_inputs; +my $scan_index_to_use; + for my $this_cgi ( split('&',$query_cgi) ) { next unless $this_cgi; - $this_cgi =~ m/(.*=)(.*)/; + $this_cgi =~ m/(.?)=(.*)/; my $input_name = $1; my $input_value = $2; - $input_name =~ s/=$//; push @query_inputs, { input_name => $input_name, input_value => $input_value }; + if ($input_name eq 'idx') { + $scan_index_to_use = $input_value; # unless $scan_index_to_use; + } } -$template->param ( QUERY_INPUTS => \@query_inputs ); +$template->param ( QUERY_INPUTS => \@query_inputs, + scan_index_to_use => $scan_index_to_use ); ## parse the limit_cgi string and put it into a form suitable for s my @limit_inputs; @@ -432,7 +505,7 @@ my $results_hashref; if (C4::Context->preference('NoZebra')) { $query=~s/yr(:|=)\s*([\d]{1,4})-([\d]{1,4})/(yr>=$2 and yr<=$3)/g; $simple_query=~s/yr\s*(:|=)([\d]{1,4})-([\d]{1,4})/(yr>=$2 and yr<=$3)/g; - warn $query; + # warn $query; eval { ($error, $results_hashref, $facets) = NZgetRecords($query,$simple_query,\@sort_by,\@servers,$results_per_page,$offset,$expanded_facet,$branches,$query_type,$scan); }; @@ -441,44 +514,18 @@ if (C4::Context->preference('NoZebra')) { ($error, $results_hashref, $facets) = getRecords($query,$simple_query,\@sort_by,\@servers,$results_per_page,$offset,$expanded_facet,$branches,$query_type,$scan); }; } +# This sorts the facets into alphabetical order +if ($facets) { + foreach my $f (@$facets) { + $f->{facets} = [ sort { uc($a->{facet_title_value}) cmp uc($b->{facet_title_value}) } @{ $f->{facets} } ]; + } +} if ($@ || $error) { $template->param(query_error => $error.$@); - output_html_with_http_headers $cgi, $cookie, $template->output; exit; } -# FIXME: This belongs in tools/ not in the primary search results page -my $op=$cgi->param("operation"); -if ($op eq "bulkedit"){ - my ($countchanged,$listunchanged)= - ModBiblios($results_hashref->{'biblioserver'}->{"RECORDS"}, - $params->{"tagsubfield"}, - $params->{"inputvalue"}, - $params->{"targetvalue"}, - $params->{"test"} - ); - $template->param(bulkeditresults=>1, - tagsubfield=>$params->{"tagsubfield"}, - inputvalue=>$params->{"inputvalue"}, - targetvalue=>$params->{"targetvalue"}, - countchanged=>$countchanged, - countunchanged=>scalar(@$listunchanged), - listunchanged=>$listunchanged); - - if (C4::Context->userenv->{'flags'}==1 ||(C4::Context->userenv->{'flags'} & ( 2**9 ) )){ - #Edit Catalogue Permissions - my $editable_subfields = GetManagedTagSubfields(); - # change '--' to '—' to avoid escaping issues - for (my $i = 0; $i <= $#{$editable_subfields}; $i++) { - $editable_subfields->[$i]->{subfielddesc} =~ s/--/—/g; - $editable_subfields->[$i]->{tagdesc} =~ s/--/—/g; - } - $template->param(bulkedit => 1); - $template->param(tagsubfields=>$editable_subfields); - } -} - # At this point, each server has given us a result set # now we build that set for template display my @sup_results_array; @@ -487,20 +534,27 @@ for (my $i=0;$i<@servers;$i++) { if ($server =~/biblioserver/) { # this is the local bibliographic server $hits = $results_hashref->{$server}->{"hits"}; my $page = $cgi->param('page') || 0; - my @newresults = searchResults( $query_desc,$hits,$results_per_page,$offset,@{$results_hashref->{$server}->{"RECORDS"}}); + my @newresults = searchResults('intranet', $query_desc, $hits, $results_per_page, $offset, $scan, + @{$results_hashref->{$server}->{"RECORDS"}}); $total = $total + $results_hashref->{$server}->{"hits"}; ## If there's just one result, redirect to the detail page if ($total == 1) { - my $biblionumber=@newresults[0]->{biblionumber}; - if (C4::Context->preference('IntranetBiblioDefaultView') eq 'isbd') { + my $biblionumber = $newresults[0]->{biblionumber}; + my $defaultview = C4::Context->preference('IntranetBiblioDefaultView'); + my $views = { C4::Search::enabled_staff_search_views }; + if ($defaultview eq 'isbd' && $views->{can_view_ISBD}) { print $cgi->redirect("/cgi-bin/koha/catalogue/ISBDdetail.pl?biblionumber=$biblionumber"); - } elsif (C4::Context->preference('IntranetBiblioDefaultView') eq 'marc') { + } elsif ($defaultview eq 'marc' && $views->{can_view_MARC}) { print $cgi->redirect("/cgi-bin/koha/catalogue/MARCdetail.pl?biblionumber=$biblionumber"); + } elsif ($defaultview eq 'labeled_marc' && $views->{can_view_labeledMARC}) { + print $cgi->redirect("/cgi-bin/koha/catalogue/labeledMARCdetail.pl?biblionumber=$biblionumber"); } else { print $cgi->redirect("/cgi-bin/koha/catalogue/detail.pl?biblionumber=$biblionumber"); } exit; } + + if ($hits) { $template->param(total => $hits); my $limit_cgi_not_availablity = $limit_cgi; @@ -510,6 +564,9 @@ for (my $i=0;$i<@servers;$i++) { $template->param(query_cgi => $query_cgi); $template->param(query_desc => $query_desc); $template->param(limit_desc => $limit_desc); + $template->param(offset => $offset); + $template->param(DisplayMultiPlaceHold => $DisplayMultiPlaceHold); + $template->param (z3950_search_params => C4::Search::z3950_search_args($query_desc)); if ($query_desc || $limit_desc) { $template->param(searchdesc => 1); } @@ -547,6 +604,7 @@ for (my $i=0;$i<@servers;$i++) { } } + # now, show twenty pages, with the current one smack in the middle else { for (my $i=$current_page_number; $i<=($current_page_number + 20 );$i++) { @@ -557,17 +615,20 @@ for (my $i=0;$i<@servers;$i++) { push @page_numbers, { offset => $this_offset, pg => $this_page_number, highlight => $highlight, sort_by => join " ",@sort_by }; } } - } # FIXME: no previous_page_offset when pages < 2 $template->param( PAGE_NUMBERS => \@page_numbers, previous_page_offset => $previous_page_offset) unless $pages < 2; $template->param( next_page_offset => $next_page_offset) unless $pages eq $current_page_number; } + + # no hits else { $template->param(searchdesc => 1,query_desc => $query_desc,limit_desc => $limit_desc); + $template->param (z3950_search_params => C4::Search::z3950_search_args($z3950par || $query_desc)); } + } # end of the if local # asynchronously search the authority server @@ -581,8 +642,7 @@ for (my $i=0;$i<@servers;$i++) { 'link' => "&idx=an&q=".$marc_record_object->field('001')->as_string(), }; } - my $servername = $server; - push @sup_results_array, { servername => $servername, + push @sup_results_array, { servername => $server, inner_sup_results_loop => \@inner_sup_results_array} if @inner_sup_results_array; } # FIXME: can add support for other targets as needed here @@ -596,6 +656,7 @@ $template->param( total => $total, opacfacets => 1, facets_loop => $facets, + displayFacetCount=> C4::Context->preference('displayFacetCount')||0, scan => $scan, search_error => $error, ); @@ -604,51 +665,24 @@ if ($query_desc || $limit_desc) { $template->param(searchdesc => 1); } -## Now let's find out if we have any supplemental data to show the user -# and in the meantime, save the current query for statistical purposes, etc. -my $koha_spsuggest; # a flag to tell if we've got suggestions coming from Koha -my @koha_spsuggest; # place we store the suggestions to be returned to the template as LOOP -my $phrases = $query_desc; -my $ipaddress; - -if ( C4::Context->preference("kohaspsuggest") ) { - my ($suggest_host, $suggest_dbname, $suggest_user, $suggest_pwd) = split(':', C4::Context->preference("kohaspsuggest")); - eval { - my $koha_spsuggest_dbh; - # FIXME: this needs to be moved to Context.pm - eval { - $koha_spsuggest_dbh=DBI->connect("DBI:mysql:$suggest_dbname:$suggest_host","$suggest_user","$suggest_pwd"); - }; - if ($@) { - warn "can't connect to spsuggest db"; - } - else { - my $koha_spsuggest_insert = "INSERT INTO phrase_log(phr_phrase,phr_resultcount,phr_ip) VALUES(?,?,?)"; - my $koha_spsuggest_query = "SELECT display FROM distincts WHERE strcmp(soundex(suggestion), soundex(?)) = 0 order by soundex(suggestion) limit 0,5"; - my $koha_spsuggest_sth = $koha_spsuggest_dbh->prepare($koha_spsuggest_query); - $koha_spsuggest_sth->execute($phrases); - while (my $spsuggestion = $koha_spsuggest_sth->fetchrow_array) { - $spsuggestion =~ s/(:|\/)//g; - my %line; - $line{spsuggestion} = $spsuggestion; - push @koha_spsuggest,\%line; - $koha_spsuggest = 1; - } +# VI. BUILD THE TEMPLATE - # Now save the current query - $koha_spsuggest_sth=$koha_spsuggest_dbh->prepare($koha_spsuggest_insert); - #$koha_spsuggest_sth->execute($phrases,$results_per_page,$ipaddress); - $koha_spsuggest_sth->finish; +# Build drop-down list for 'Add To:' menu... - $template->param( koha_spsuggest => $koha_spsuggest ) unless $hits; - $template->param( SPELL_SUGGEST => \@koha_spsuggest, - ); - } - }; - if ($@) { - warn "Kohaspsuggest failure:".$@; - } +my $row_count = 10; # FIXME:This probably should be a syspref +my ($pubshelves, $total) = GetRecentShelves(2, $row_count, undef); +my ($barshelves, $total) = GetRecentShelves(1, $row_count, $borrowernumber); + +if (@{$pubshelves}) { + $template->param( addpubshelves => scalar @{$pubshelves}); + $template->param( addpubshelvesloop => $pubshelves); } -# VI. BUILD THE TEMPLATE +if (@{$barshelves}) { + $template->param( addbarshelves => scalar @{$barshelves}); + $template->param( addbarshelvesloop => $barshelves); +} + + + output_html_with_http_headers $cgi, $cookie, $template->output;