X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FSearch.pm;h=5d6816557498bb66df5285d271c0ae1dd80c7d41;hb=86a0a7d80b71908582dfc40c981734c5828112fc;hp=4de0931fe0f64861c8cd28f7738b8493cb450b4d;hpb=0dd1ac40a0df984bee6583f13f80744b539b8f37;p=srvgit diff --git a/C4/Search.pm b/C4/Search.pm index 4de0931fe0..5d68165574 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -2,46 +2,45 @@ package C4::Search; # 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., 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, see . -use strict; -#use warnings; FIXME - Bug 2505 +use Modern::Perl; require Exporter; use C4::Context; use C4::Biblio; # GetMarcFromKohaField, GetBiblioData use C4::Koha; # getFacets +use Koha::DateUtils; +use Koha::Libraries; use Lingua::Stem; use C4::Search::PazPar2; use XML::Simple; -use C4::Dates qw(format_date); -use C4::Members qw(GetHideLostItemsPreference); use C4::XSLT; -use C4::Branch; use C4::Reserves; # GetReserveStatus use C4::Debug; use C4::Charset; +use Koha::AuthorisedValues; +use Koha::ItemTypes; +use Koha::Libraries; +use Koha::Patrons; use YAML; use URI::Escape; use Business::ISBN; use MARC::Record; use MARC::Field; -use utf8; -use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG); +use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG); -# set the version for version checking BEGIN { - $VERSION = 3.07.00.049; $DEBUG = ($ENV{DEBUG}) ? 1 : 0; } @@ -70,7 +69,6 @@ This module provides searching functions for Koha's bibliographic databases &buildQuery &GetDistinctValues &enabled_staff_search_views - &PurgeSearchHistory ); # make all your functions, whether exported or not; @@ -86,7 +84,7 @@ This function attempts to find duplicate records using a hard-coded, fairly simp sub FindDuplicate { my ($record) = @_; my $dbh = C4::Context->dbh; - my $result = TransformMarcToKoha( $dbh, $record, '' ); + my $result = TransformMarcToKoha( $record, '' ); my $sth; my $query; my $search; @@ -148,7 +146,7 @@ sub FindDuplicate { $possible_duplicate_record ); - my $result = TransformMarcToKoha( $dbh, $marcrecord, '' ); + my $result = TransformMarcToKoha( $marcrecord, '' ); # FIXME :: why 2 $biblionumber ? if ($result) { @@ -162,7 +160,7 @@ sub FindDuplicate { =head2 SimpleSearch -( $error, $results, $total_hits ) = SimpleSearch( $query, $offset, $max_results, [@servers] ); +( $error, $results, $total_hits ) = SimpleSearch( $query, $offset, $max_results, [@servers], [%options] ); This function provides a simple search API on the bibliographic catalog @@ -172,8 +170,9 @@ This function provides a simple search API on the bibliographic catalog * $query can be a simple keyword or a complete CCL query * @servers is optional. Defaults to biblioserver as found in koha-conf.xml - * $offset - If present, represents the number of records at the beggining to omit. Defaults to 0 + * $offset - If present, represents the number of records at the beginning to omit. Defaults to 0 * $max_results - if present, determines the maximum number of records to fetch. undef is All. defaults to undef. + * %options is optional. (e.g. "skip_normalize" allows you to skip changing : to = ) =item C @@ -204,7 +203,7 @@ my @results; for my $r ( @{$marcresults} ) { my $marcrecord = MARC::File::USMARC::decode($r); - my $biblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,q{}); + my $biblio = TransformMarcToKoha($marcrecord,q{}); #build the iarray of hashs for the template. push @results, { @@ -223,7 +222,7 @@ $template->param(result=>\@results); =cut sub SimpleSearch { - my ( $query, $offset, $max_results, $servers ) = @_; + my ( $query, $offset, $max_results, $servers, %options ) = @_; return ( 'No query entered', undef, undef ) unless $query; # FIXME hardcoded value. See catalog/search.pl & opac-search.pl too. @@ -245,12 +244,12 @@ sub SimpleSearch { eval { $zconns[$i] = C4::Context->Zconn( $servers[$i], 1 ); if ($QParser) { - $query =~ s/=/:/g; + $query =~ s/=/:/g unless $options{skip_normalize}; $QParser->parse( $query ); $query = $QParser->target_syntax($servers[$i]); $zoom_queries[$i] = new ZOOM::Query::PQF( $query, $zconns[$i]); } else { - $query =~ s/:/=/g; + $query =~ s/:/=/g unless $options{skip_normalize}; $zoom_queries[$i] = new ZOOM::Query::CCL2RPN( $query, $zconns[$i]); } $tmpresults[$i] = $zconns[$i]->search( $zoom_queries[$i] ); @@ -312,26 +311,27 @@ sub SimpleSearch { ( undef, $results_hashref, \@facets_loop ) = getRecords ( $koha_query, $simple_query, $sort_by_ref, $servers_ref, - $results_per_page, $offset, $expanded_facet, $branches,$itemtypes, - $query_type, $scan + $results_per_page, $offset, $branches, $itemtypes, + $query_type, $scan, $opac ); The all singing, all dancing, multi-server, asynchronous, scanning, searching, record nabbing, facet-building -See verbse embedded documentation. +See verbose embedded documentation. =cut sub getRecords { my ( $koha_query, $simple_query, $sort_by_ref, $servers_ref, - $results_per_page, $offset, $expanded_facet, $branches, - $itemtypes, $query_type, $scan, $opac + $results_per_page, $offset, $branches, $itemtypes, + $query_type, $scan, $opac ) = @_; my @servers = @$servers_ref; my @sort_by = @$sort_by_ref; + $offset = 0 if $offset < 0; # Initialize variables for the ZOOM connection and results object my $zconn; @@ -339,6 +339,9 @@ sub getRecords { my @results; my $results_hashref = (); + # TODO simplify this structure ( { branchcode => $branchname } is enought) and remove this parameter + $branches ||= { map { $_->branchcode => { branchname => $_->branchname } } Koha::Libraries->search }; + # Initialize variables for the faceted results objects my $facets_counter = {}; my $facets_info = {}; @@ -512,8 +515,6 @@ sub getRecords { keys %$facets_counter ) { - my $expandable; - my $number_of_facets; my @this_facets_array; for my $one_facet ( sort { @@ -523,87 +524,80 @@ sub getRecords { } keys %{ $facets_counter->{$link_value} } ) { - $number_of_facets++; - if ( ( $number_of_facets <= 5 ) - || ( $expanded_facet eq $link_value ) - || ( $facets_info->{$link_value}->{'expanded'} ) - ) - { - # Sanitize the link value : parenthesis, question and exclamation mark will cause errors with CCL - my $facet_link_value = $one_facet; - $facet_link_value =~ s/[()!?¡¿؟]/ /g; - - # fix the length that will display in the label, - my $facet_label_value = $one_facet; - my $facet_max_length = C4::Context->preference( - 'FacetLabelTruncationLength') - || 20; - $facet_label_value = - substr( $one_facet, 0, $facet_max_length ) - . "..." - if length($facet_label_value) > - $facet_max_length; - - # if it's a branch, label by the name, not the code, - if ( $link_value =~ /branch/ ) { - if ( defined $branches - && ref($branches) eq "HASH" - && defined $branches->{$one_facet} - && ref( $branches->{$one_facet} ) eq - "HASH" ) - { - $facet_label_value = - $branches->{$one_facet} - ->{'branchname'}; - } - else { - $facet_label_value = "*"; - } + my $facet_link_value = $one_facet; + $facet_link_value =~ s/[()!?¡¿؟]/ /g; + + # fix the length that will display in the label, + my $facet_label_value = $one_facet; + my $facet_max_length = C4::Context->preference( + 'FacetLabelTruncationLength') + || 20; + $facet_label_value = + substr( $one_facet, 0, $facet_max_length ) + . "..." + if length($facet_label_value) > + $facet_max_length; + + # if it's a branch, label by the name, not the code, + if ( $link_value =~ /branch/ ) { + if ( defined $branches + && ref($branches) eq "HASH" + && defined $branches->{$one_facet} + && ref( $branches->{$one_facet} ) eq + "HASH" ) + { + $facet_label_value = + $branches->{$one_facet} + ->{'branchname'}; } - - # if it's a itemtype, label by the name, not the code, - if ( $link_value =~ /itype/ ) { - if ( defined $itemtypes - && ref($itemtypes) eq "HASH" - && defined $itemtypes->{$one_facet} - && ref( $itemtypes->{$one_facet} ) eq - "HASH" ) - { - $facet_label_value = - $itemtypes->{$one_facet} - ->{'description'}; - } + else { + $facet_label_value = "*"; } + } - # also, if it's a location code, use the name instead of the code - if ( $link_value =~ /location/ ) { + # if it's a itemtype, label by the name, not the code, + if ( $link_value =~ /itype/ ) { + if ( defined $itemtypes + && ref($itemtypes) eq "HASH" + && defined $itemtypes->{$one_facet} + && ref( $itemtypes->{$one_facet} ) eq + "HASH" ) + { $facet_label_value = - GetKohaAuthorisedValueLib( 'LOC', - $one_facet, $opac ); + $itemtypes->{$one_facet} + ->{translated_description}; } + } - # but we're down with the whole label being in the link's title. - push @this_facets_array, - { - facet_count => - $facets_counter->{$link_value} - ->{$one_facet}, - facet_label_value => $facet_label_value, - facet_title_value => $one_facet, - facet_link_value => $facet_link_value, - type_link_value => $link_value, - } - if ($facet_label_value); + # also, if it's a location code, use the name instead of the code + if ( $link_value =~ /location/ ) { + # TODO Retrieve all authorised values at once, instead of 1 query per entry + my $av = Koha::AuthorisedValues->search({ category => 'LOC', authorised_value => $one_facet }); + $facet_label_value = $av->count ? $av->next->opac_description : ''; + } + + # also, if it's a collection code, use the name instead of the code + if ( $link_value =~ /ccode/ ) { + # TODO Retrieve all authorised values at once, instead of 1 query per entry + my $av = Koha::AuthorisedValues->search({ category => 'CCODE', authorised_value => $one_facet }); + $facet_label_value = $av->count ? $av->next->opac_description : ''; } - } - # handle expanded option - unless ( $facets_info->{$link_value}->{'expanded'} ) { - $expandable = 1 - if ( ( $number_of_facets > 5 ) - && ( $expanded_facet ne $link_value ) ); + # but we're down with the whole label being in the link's title. + push @this_facets_array, + { + facet_count => + $facets_counter->{$link_value} + ->{$one_facet}, + facet_label_value => $facet_label_value, + facet_title_value => $one_facet, + facet_link_value => $facet_link_value, + type_link_value => $link_value, + } + if ($facet_label_value); } + push @facets_loop, { type_link_value => $link_value, @@ -612,20 +606,27 @@ sub getRecords { . $facets_info->{$link_value}->{'label_value'} => 1, facets => \@this_facets_array, - expandable => $expandable, - expand => $link_value, } unless ( ( $facets_info->{$link_value}->{'label_value'} =~ /Libraries/ ) - and ( C4::Context->preference('singleBranchMode') ) + and ( Koha::Libraries->search->count == 1 ) ); } } } ); + + # This sorts the facets into alphabetical order + if (@facets_loop) { + foreach my $f (@facets_loop) { + $f->{facets} = [ sort { uc($a->{facet_label_value}) cmp uc($b->{facet_label_value}) } @{ $f->{facets} } ]; + } + @facets_loop = sort {$a->{expand} cmp $b->{expand}} @facets_loop; + } + return ( undef, $results_hashref, \@facets_loop ); } @@ -634,11 +635,9 @@ sub GetFacets { my $rs = shift; my $facets; - my $indexing_mode = C4::Context->config('zebra_bib_index_mode') // 'dom'; my $use_zebra_facets = C4::Context->config('use_zebra_facets') // 0; - if ( $indexing_mode eq 'dom' && - $use_zebra_facets ) { + if ( $use_zebra_facets ) { $facets = _get_facets_from_zebra( $rs ); } else { $facets = _get_facets_from_records( $rs ); @@ -834,7 +833,6 @@ sub _get_facets_info { for my $facet ( @$facets ) { $facets_info->{ $facet->{ idx } }->{ label_value } = $facet->{ label }; - $facets_info->{ $facet->{ idx } }->{ expanded } = $facet->{ expanded }; } return $facets_info; @@ -843,9 +841,10 @@ sub _get_facets_info { sub pazGetRecords { my ( $koha_query, $simple_query, $sort_by_ref, $servers_ref, - $results_per_page, $offset, $expanded_facet, $branches, - $query_type, $scan + $results_per_page, $offset, $branches, $query_type, + $scan ) = @_; + #NOTE: Parameter $branches is not used here ! my $paz = C4::Search::PazPar2->new(C4::Context->config('pazpar2url')); $paz->init(); @@ -913,32 +912,6 @@ sub pazGetRecords { return ( undef, $results_hashref, \@facets_loop ); } -# STOPWORDS -sub _remove_stopwords { - my ( $operand, $index ) = @_; - my @stopwords_removed; - - # phrase and exact-qualified indexes shouldn't have stopwords removed - if ( $index !~ m/,(phr|ext)/ ) { - -# remove stopwords from operand : parse all stopwords & remove them (case insensitive) -# we use IsAlpha unicode definition, to deal correctly with diacritics. -# otherwise, a French word like "leçon" woudl be split into "le" "çon", "le" -# is a stopword, we'd get "çon" and wouldn't find anything... -# - foreach ( keys %{ C4::Context->stopwords } ) { - next if ( $_ =~ /(and|or|not)/ ); # don't remove operators - if ( my ($matched) = ($operand =~ - /([^\X\p{isAlnum}]\Q$_\E[^\X\p{isAlnum}]|[^\X\p{isAlnum}]\Q$_\E$|^\Q$_\E[^\X\p{isAlnum}])/gi)) - { - $operand =~ s/\Q$matched\E/ /gi; - push @stopwords_removed, $_; - } - } - } - return ( $operand, \@stopwords_removed ); -} - # TRUNCATION sub _detect_truncation { my ( $operand, $index ) = @_; @@ -975,6 +948,9 @@ sub _build_stemmed_operand { require Lingua::Stem::Snowball ; my $stemmed_operand=q{}; + # Stemmer needs language + return $operand unless $lang; + # If operand contains a digit, it is almost certainly an identifier, and should # not be stemmed. This is particularly relevant for ISBNs and ISSNs, which # can contain the letter "X" - for example, _build_stemmend_operand would reduce @@ -1049,6 +1025,11 @@ sub _build_weighted_query { $weighted_query .= "an=\"$operand\""; } + # If the index is numeric, don't autoquote it. + elsif ( $index =~ /,st-numeric$/ ) { + $weighted_query .= " $index=$operand"; + } + # If the index already has more than one qualifier, wrap the operand # in quotes and pass it back (assumption is that the user knows what they # are doing and won't appreciate us mucking up their query @@ -1088,6 +1069,8 @@ sub getIndexes{ 'an', 'Any', 'at', + 'arl', + 'arp', 'au', 'aub', 'aud', @@ -1132,8 +1115,11 @@ sub getIndexes{ 'date-entered-on-file', 'Date-of-acquisition', 'Date-of-publication', + 'Date-time-last-modified', 'Dewey-classification', 'Dissertation-information', + 'diss', + 'dtlm', 'EAN', 'extent', 'fic', @@ -1148,9 +1134,13 @@ sub getIndexes{ 'Heading-use-subject-added-entry', 'Host-item', 'id-other', + 'ident', + 'Identifier-standard', 'Illustration-code', 'Index-term-genre', 'Index-term-uncontrolled', + 'Interest-age-level', + 'Interest-grade-level', 'ISBN', 'isbn', 'ISSN', @@ -1165,6 +1155,7 @@ sub getIndexes{ 'LC-card-number', 'lcn', 'lex', + 'lexile-number', 'llength', 'ln', 'ln-audio', @@ -1188,6 +1179,7 @@ sub getIndexes{ 'notes', 'ns', 'nt', + 'Other-control-number', 'pb', 'Personal-name', 'Personal-name-heading', @@ -1199,6 +1191,9 @@ sub getIndexes{ 'popularity', 'pubdate', 'Publisher', + 'Provider', + 'pv', + 'Reading-grade-level', 'Record-control-number', 'rcn', 'Record-type', @@ -1215,15 +1210,9 @@ sub getIndexes{ 'Subject-subdivision', 'Summary', 'Suppress', - 'su-chrono', - 'su-corp', - 'su-conf', 'su-geo', - 'su-form', - 'su-genre', 'su-na', 'su-to', - 'su-ti', 'su-ut', 'ut', 'Term-genre-form', @@ -1336,12 +1325,13 @@ sub _handle_exploding_index { ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang ) = - buildQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang); + parseQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang); Shim function to ease the transition from buildQuery to a new QueryParser. This function is called at the beginning of buildQuery, and modifies buildQuery's input. If it can handle the input, it returns a query that buildQuery will not try to parse. + =cut sub parseQuery { @@ -1421,10 +1411,10 @@ sub parseQuery { $simple_query, $query_cgi, $query_desc, $limit, $limit_cgi, $limit_desc, -$stopwords_removed, $query_type ) = buildQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang); +$query_type ) = buildQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang); Build queries and limits in CCL, CGI, Human, -handle truncation, stemming, field weighting, stopwords, fuzziness, etc. +handle truncation, stemming, field weighting, fuzziness, etc. See verbose embedded documentation. @@ -1450,7 +1440,6 @@ sub buildQuery { my $auto_truncation = C4::Context->preference("QueryAutoTruncate") || 0; my $weight_fields = C4::Context->preference("QueryWeightFields") || 0; my $fuzzy_enabled = C4::Context->preference("QueryFuzzy") || 0; - my $remove_stopwords = C4::Context->preference("QueryRemoveStopwords") || 0; my $query = $operands[0]; my $simple_query = $operands[0]; @@ -1463,8 +1452,6 @@ sub buildQuery { my $limit_cgi; my $limit_desc; - my $stopwords_removed; # flag to determine if stopwords have been removed - my $cclq = 0; my $cclindexes = getIndexes(); if ( $query !~ /\s*(ccl=|pqf=|cql=)/ ) { @@ -1482,22 +1469,31 @@ sub buildQuery { # This is needed otherwise ccl= and &limit won't work together, and # this happens when selecting a subject on the opac-detail page @limits = grep {!/^$/} @limits; + my $original_q = $q; # without available part + unless ( grep { /^available$/ } @limits ) { + $q =~ s| and \( \(allrecords,AlwaysMatches=''\) and \(not-onloan-count,st-numeric >= 1\) and \(lost,st-numeric=0\) \)||; + $original_q = $q; + } if ( @limits ) { - $q .= ' and '.join(' and ', @limits); + if ( grep { /^available$/ } @limits ) { + $q .= q| and ( (allrecords,AlwaysMatches='') and (not-onloan-count,st-numeric >= 1) and (lost,st-numeric=0) )|; + delete $limits['available']; + } + $q .= ' and '.join(' and ', @limits) if @limits; } - return ( undef, $q, $q, "q=ccl=".uri_escape($q), $q, '', '', '', '', 'ccl' ); + return ( undef, $q, $q, "q=ccl=".uri_escape_utf8($q), $original_q, '', '', '', 'ccl' ); } if ( $query =~ /^cql=/ ) { - return ( undef, $', $', "q=cql=".uri_escape($'), $', '', '', '', '', 'cql' ); + return ( undef, $', $', "q=cql=".uri_escape_utf8($'), $', '', '', '', 'cql' ); } if ( $query =~ /^pqf=/ ) { if ($query_desc) { - $query_cgi = "q=".uri_escape($query_desc); + $query_cgi = "q=".uri_escape_utf8($query_desc); } else { $query_desc = $'; - $query_cgi = "q=pqf=".uri_escape($'); + $query_cgi = "q=pqf=".uri_escape_utf8($'); } - return ( undef, $', $', $query_cgi, $query_desc, '', '', '', '', 'pqf' ); + return ( undef, $', $', $query_cgi, $query_desc, '', '', '', 'pqf' ); } # pass nested queries directly @@ -1508,7 +1504,7 @@ sub buildQuery { # return ( # undef, $query, $simple_query, $query_cgi, # $query, $limit, $limit_cgi, $limit_desc, -# $stopwords_removed, 'ccl' +# 'ccl' # ); # } @@ -1526,17 +1522,16 @@ sub buildQuery { for ( my $i = 0 ; $i <= @operands ; $i++ ) { # COMBINE OPERANDS, INDEXES AND OPERATORS - if ( $operands[$i] ) { + if ( ($operands[$i] // '') ne '' ) { $operands[$i]=~s/^\s+//; # A flag to determine whether or not to add the index to the query my $indexes_set; -# If the user is sophisticated enough to specify an index, turn off field weighting, stemming, and stopword handling +# If the user is sophisticated enough to specify an index, turn off field weighting, and stemming handling if ( $operands[$i] =~ /\w(:|=)/ || $scan ) { $weight_fields = 0; $stemming = 0; - $remove_stopwords = 0; } else { $operands[$i] =~ s/\?/{?}/g; # need to escape question marks } @@ -1550,12 +1545,12 @@ sub buildQuery { #which is processed higher up in this sub. Other than that, year searches are typically #handled as limits which are not processed her either. - # Date of Publication - if ( $index =~ /yr/ ) { + # Search ranges: Date of Publication, st-numeric + if ( $index =~ /(yr|st-numeric)/ ) { #weight_fields/relevance search causes errors with date ranges #In the case of YYYY-, it will only return records with a 'yr' of YYYY (not the range) #In the case of YYYY-YYYY, it will return no results - $stemming = $auto_truncation = $weight_fields = $fuzzy_enabled = $remove_stopwords = 0; + $stemming = $auto_truncation = $weight_fields = $fuzzy_enabled = 0; } # Date of Acquisition @@ -1565,17 +1560,22 @@ sub buildQuery { #top of the results just because they have lots of item records matching that date. #Fuzzy actually only applies during _build_weighted_query, and is reset there anyway, so #irrelevant here - #remove_stopwords doesn't function anymore so is irrelevant - $stemming = $auto_truncation = $weight_fields = $fuzzy_enabled = $remove_stopwords = 0; + $stemming = $auto_truncation = $weight_fields = $fuzzy_enabled = 0; } # ISBN,ISSN,Standard Number, don't need special treatment - elsif ( $index eq 'nb' || $index eq 'ns' ) { + elsif ( $index eq 'nb' || $index eq 'ns' || $index eq 'hi' ) { ( $stemming, $auto_truncation, - $weight_fields, $fuzzy_enabled, - $remove_stopwords - ) = ( 0, 0, 0, 0, 0 ); - + $weight_fields, $fuzzy_enabled + ) = ( 0, 0, 0, 0 ); + + if ( $index eq 'nb' ) { + if ( C4::Context->preference("SearchWithISBNVariations") ) { + my @isbns = C4::Koha::GetVariationsOfISBN( $operand ); + $operands[$i] = $operand = '(nb=' . join(' OR nb=', @isbns) . ')'; + $indexes[$i] = $index = ''; + } + } } if(not $index){ @@ -1592,15 +1592,6 @@ sub buildQuery { my $index_plus = $index . $struct_attr . ':'; my $index_plus_comma = $index . $struct_attr . ','; - # Remove Stopwords - if ($remove_stopwords) { - ( $operand, $stopwords_removed ) = - _remove_stopwords( $operand, $index ); - warn "OPERAND w/out STOPWORDS: >$operand<" if $DEBUG; - warn "REMOVED STOPWORDS: @$stopwords_removed" - if ( $stopwords_removed && $DEBUG ); - } - if ($auto_truncation){ unless ( $index =~ /,(st-|phr|ext)/ ) { #FIXME only valid with LTR scripts @@ -1676,7 +1667,7 @@ sub buildQuery { query_desc => $query_desc, operator => ($operators[ $i - 1 ]) ? $operators[ $i - 1 ] : '', parsed_operand => $operand, - original_operand => ($operands[$i]) ? $operands[$i] : '', + original_operand => $operands[$i] // '', index => $index, index_plus => $index_plus, indexes_set => $indexes_set, @@ -1699,7 +1690,7 @@ sub buildQuery { ## In English: ## all records not indexed in the onloan register (zebra) and all records with a value of lost equal to 0 $availability_limit .= -"( ( allrecords,AlwaysMatches='' not onloan,AlwaysMatches='') and (lost,st-numeric=0) )"; #or ( allrecords,AlwaysMatches='' not lost,AlwaysMatches='')) )"; +"( (allrecords,AlwaysMatches='') and (not-onloan-count,st-numeric >= 1) and (lost,st-numeric=0) )"; $limit_cgi .= "&limit=available"; $limit_desc .= ""; } @@ -1711,13 +1702,13 @@ sub buildQuery { if ( $k !~ /mc-i(tem)?type/ ) { # in case the mc-ccode value has complicating chars like ()'s inside it we wrap in quotes $this_limit =~ tr/"//d; - $this_limit = $k.":\"".$v."\""; + $this_limit = $k.":'".$v."'"; } $group_OR_limits{$k} .= " or " if $group_OR_limits{$k}; $limit_desc .= " or " if $group_OR_limits{$k}; $group_OR_limits{$k} .= "$this_limit"; - $limit_cgi .= "&limit=" . uri_escape($this_limit); + $limit_cgi .= "&limit=" . uri_escape_utf8($this_limit); $limit_desc .= " $this_limit"; } @@ -1725,12 +1716,12 @@ sub buildQuery { else { $limit .= " and " if $limit || $query; $limit .= "$this_limit"; - $limit_cgi .= "&limit=" . uri_escape($this_limit); + $limit_cgi .= "&limit=" . uri_escape_utf8($this_limit); if ($this_limit =~ /^branch:(.+)/) { my $branchcode = $1; - my $branchname = GetBranchName($branchcode); - if (defined $branchname) { - $limit_desc .= " branch:$branchname"; + my $library = Koha::Libraries->find( $branchcode ); + if (defined $library) { + $limit_desc .= " branch:" . $library->branchname; } else { $limit_desc .= " $this_limit"; } @@ -1784,10 +1775,11 @@ sub buildQuery { warn "LIMIT DESC:" . $limit_desc; warn "---------\nLeave buildQuery\n---------"; } + return ( undef, $query, $simple_query, $query_cgi, $query_desc, $limit, $limit_cgi, $limit_desc, - $stopwords_removed, $query_type + $query_type ); } @@ -1815,9 +1807,9 @@ sub _build_initial_query { #e.g. " and kw,wrdl:test" $params->{query} .= $operator . $operand; - $params->{query_cgi} .= "&op=".uri_escape($operator) if $operator; - $params->{query_cgi} .= "&idx=".uri_escape($params->{index}) if $params->{index}; - $params->{query_cgi} .= "&q=".uri_escape($params->{original_operand}) if $params->{original_operand}; + $params->{query_cgi} .= "&op=".uri_escape_utf8($operator) if $operator; + $params->{query_cgi} .= "&idx=".uri_escape_utf8($params->{index}) if $params->{index}; + $params->{query_cgi} .= "&q=".uri_escape_utf8($params->{original_operand}) if $params->{original_operand}; #e.g. " and kw,wrdl: test" $params->{query_desc} .= $operator . $params->{index_plus} . " " . $params->{original_operand}; @@ -1846,54 +1838,39 @@ sub searchResults { require C4::Items; - $search_context = 'opac' if !$search_context || $search_context ne 'intranet'; + $search_context->{'interface'} = 'opac' if !$search_context->{'interface'} || $search_context->{'interface'} ne 'intranet'; my ($is_opac, $hidelostitems); - if ($search_context eq 'opac') { + if ($search_context->{'interface'} eq 'opac') { $hidelostitems = C4::Context->preference('hidelostitems'); $is_opac = 1; } #Build branchnames hash - #find branchname - #get branch information..... - my %branches; - my $bsth =$dbh->prepare("SELECT branchcode,branchname FROM branches"); # FIXME : use C4::Branch::GetBranches - $bsth->execute(); - while ( my $bdata = $bsth->fetchrow_hashref ) { - $branches{ $bdata->{'branchcode'} } = $bdata->{'branchname'}; - } + my %branches = map { $_->branchcode => $_->branchname } Koha::Libraries->search({}, { order_by => 'branchname' }); + # FIXME - We build an authorised values hash here, using the default framework # though it is possible to have different authvals for different fws. - my $shelflocations =GetKohaAuthorisedValues('items.location',''); + my $shelflocations = + { map { $_->{authorised_value} => $_->{lib} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.location' } ) }; # get notforloan authorised value list (see $shelflocations FIXME) - my $notforloan_authorised_value = GetAuthValCode('items.notforloan',''); - - #Build itemtype hash - #find itemtype & itemtype image - my %itemtypes; - $bsth = - $dbh->prepare( - "SELECT itemtype,description,imageurl,summary,notforloan FROM itemtypes" - ); - $bsth->execute(); - while ( my $bdata = $bsth->fetchrow_hashref ) { - foreach (qw(description imageurl summary notforloan)) { - $itemtypes{ $bdata->{'itemtype'} }->{$_} = $bdata->{$_}; - } - } + my $av = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.notforloan', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] }); + my $notforloan_authorised_value = $av->count ? $av->next->authorised_value : undef; + + #Get itemtype hash + my $itemtypes = Koha::ItemTypes->search_with_localization; + my %itemtypes = map { $_->{itemtype} => $_ } @{ $itemtypes->unblessed }; #search item field code - my ($itemtag, undef) = &GetMarcFromKohaField( "items.itemnumber", "" ); + my ($itemtag, undef) = &GetMarcFromKohaField( "items.itemnumber" ); ## find column names of items related to MARC - my $sth2 = $dbh->prepare("SHOW COLUMNS FROM items"); - $sth2->execute; my %subfieldstosearch; - while ( ( my $column ) = $sth2->fetchrow ) { + my @columns = Koha::Database->new()->schema()->resultset('Item')->result_source->columns; + for my $column ( @columns ) { my ( $tagfield, $tagsubfield ) = - &GetMarcFromKohaField( "items." . $column, "" ); + &GetMarcFromKohaField( "items." . $column ); if ( defined $tagsubfield ) { $subfieldstosearch{$column} = $tagsubfield; } @@ -1910,7 +1887,27 @@ sub searchResults { my $marcflavour = C4::Context->preference("marcflavour"); # We get the biblionumber position in MARC - my ($bibliotag,$bibliosubf)=GetMarcFromKohaField('biblio.biblionumber',''); + my ($bibliotag,$bibliosubf)=GetMarcFromKohaField( 'biblio.biblionumber' ); + + # set stuff for XSLT processing here once, not later again for every record we retrieved + my $xslfile; + my $xslsyspref; + if( $is_opac ){ + $xslsyspref = "OPACXSLTResultsDisplay"; + $xslfile = C4::Context->preference( $xslsyspref ); + } else { + $xslsyspref = "XSLTResultsDisplay"; + $xslfile = C4::Context->preference( $xslsyspref ) || "default"; + } + my $lang = $xslfile ? C4::Languages::getlanguage() : undef; + my $sysxml = $xslfile ? C4::XSLT::get_xslt_sysprefs() : undef; + + my $userenv = C4::Context->userenv; + my $logged_in_user + = ( defined $userenv and $userenv->{number} ) + ? Koha::Patrons->find( $userenv->{number} ) + : undef; + my $patron_category_hide_lost_items = ($logged_in_user) ? $logged_in_user->category->hidelostitems : 0; # loop through all of the records we've retrieved for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) { @@ -1937,14 +1934,14 @@ sub searchResults { : $bibliotag < 10 ? GetFrameworkCode($marcrecord->field($bibliotag)->data) : GetFrameworkCode($marcrecord->subfield($bibliotag,$bibliosubf)); - my $oldbiblio = TransformMarcToKoha( $dbh, $marcrecord, $fw ); - $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord, $fw); + + SetUTF8Flag($marcrecord); + my $oldbiblio = TransformMarcToKoha( $marcrecord, $fw ); $oldbiblio->{result_number} = $i + 1; # add imageurl to itemtype if there is one - $oldbiblio->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} ); + $oldbiblio->{imageurl} = getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} ); - $oldbiblio->{'authorised_value_images'} = ($search_context eq 'opac' && C4::Context->preference('AuthorisedValueImages')) || ($search_context eq 'intranet' && C4::Context->preference('StaffAuthorisedValueImages')) ? C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) ) : []; $oldbiblio->{normalized_upc} = GetNormalizedUPC( $marcrecord,$marcflavour); $oldbiblio->{normalized_ean} = GetNormalizedEAN( $marcrecord,$marcflavour); $oldbiblio->{normalized_oclc} = GetNormalizedOCLCNumber($marcrecord,$marcflavour); @@ -1953,10 +1950,11 @@ sub searchResults { # edition information, if any $oldbiblio->{edition} = $oldbiblio->{editionstatement}; - $oldbiblio->{description} = $itemtypes{ $oldbiblio->{itemtype} }->{description}; + $oldbiblio->{description} = $itemtypes{ $oldbiblio->{itemtype} }->{translated_description}; # Build summary if there is one (the summary is defined in the itemtypes table) - # FIXME: is this used anywhere, I think it can be commented out? -- JF - if ( $itemtypes{ $oldbiblio->{itemtype} }->{summary} ) { + + # FIXME: this is only used in the deprecated non-XLST opac results + if ( !$xslfile && $is_opac && $itemtypes{ $oldbiblio->{itemtype} }->{summary} ) { my $summary = $itemtypes{ $oldbiblio->{itemtype} }->{summary}; my @fields = $marcrecord->fields(); @@ -1987,12 +1985,7 @@ sub searchResults { if($marcrecord->field($1)){ my @repl = $marcrecord->field($1)->subfield($2); my $subfieldvalue = $repl[$i]; - - if (! utf8::is_utf8($subfieldvalue)) { - utf8::decode($subfieldvalue); - } - - $newline =~ s/\[$tag\]/$subfieldvalue/g; + $newline =~ s/\[$tag\]/$subfieldvalue/g; } } $newsummary .= "$newline\n"; @@ -2007,27 +2000,31 @@ sub searchResults { # Pull out the items fields my @fields = $marcrecord->field($itemtag); my $marcflavor = C4::Context->preference("marcflavour"); + # adding linked items that belong to host records - my $analyticsfield = '773'; - if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') { - $analyticsfield = '773'; - } elsif ($marcflavor eq 'UNIMARC') { - $analyticsfield = '461'; - } - foreach my $hostfield ( $marcrecord->field($analyticsfield)) { - my $hostbiblionumber = $hostfield->subfield("0"); - my $linkeditemnumber = $hostfield->subfield("9"); - if(!$hostbiblionumber eq undef){ - my $hostbiblio = GetMarcBiblio($hostbiblionumber, 1); - my ($itemfield, undef) = GetMarcFromKohaField( 'items.itemnumber', GetFrameworkCode($hostbiblionumber) ); - if(!$hostbiblio eq undef){ - my @hostitems = $hostbiblio->field($itemfield); - foreach my $hostitem (@hostitems){ - if ($hostitem->subfield("9") eq $linkeditemnumber){ - my $linkeditem =$hostitem; - # append linked items if they exist - if (!$linkeditem eq undef){ - push (@fields, $linkeditem);} + if ( C4::Context->preference('EasyAnalyticalRecords') ) { + my $analyticsfield = '773'; + if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') { + $analyticsfield = '773'; + } elsif ($marcflavor eq 'UNIMARC') { + $analyticsfield = '461'; + } + foreach my $hostfield ( $marcrecord->field($analyticsfield)) { + my $hostbiblionumber = $hostfield->subfield("0"); + my $linkeditemnumber = $hostfield->subfield("9"); + if( $hostbiblionumber ) { + my $hostbiblio = GetMarcBiblio({ + biblionumber => $hostbiblionumber, + embed_items => 1 }); + my ($itemfield, undef) = GetMarcFromKohaField( 'items.itemnumber' ); + if( $hostbiblio ) { + my @hostitems = $hostbiblio->field($itemfield); + foreach my $hostitem (@hostitems){ + if ($hostitem->subfield("9") eq $linkeditemnumber){ + my $linkeditem =$hostitem; + # append linked items if they exist + push @fields, $linkeditem if $linkeditem; + } } } } @@ -2070,7 +2067,7 @@ sub searchResults { foreach my $code ( keys %subfieldstosearch ) { $item->{$code} = $field->subfield( $subfieldstosearch{$code} ); } - $item->{description} = $itemtypes{ $item->{itype} }{description}; + $item->{description} = $itemtypes{ $item->{itype} }{translated_description}; # OPAC hidden items if ($is_opac) { @@ -2080,7 +2077,7 @@ sub searchResults { next; } # hidden based on OpacHiddenItems syspref - my @hi = C4::Items::GetHiddenItemnumbers($item); + my @hi = C4::Items::GetHiddenItemnumbers({ items=> [ $item ], borcat => $search_context->{category} }); if (scalar @hi) { push @hiddenitems, @hi; $hideatopac_count++; @@ -2101,22 +2098,27 @@ sub searchResults { my $prefix = $item->{$hbranch} . '--' . $item->{location} . $item->{itype} . $item->{itemcallnumber}; # For each grouping of items (onloan, available, unavailable), we build a key to store relevant info about that item - my $userenv = C4::Context->userenv; - if ( $item->{onloan} && !(C4::Members::GetHideLostItemsPreference($userenv->{'number'}) && $item->{itemlost}) ) { + if ( $item->{onloan} + and $logged_in_user + and !( $patron_category_hide_lost_items and $item->{itemlost} ) ) + { $onloan_count++; - my $key = $prefix . $item->{onloan} . $item->{barcode}; - $onloan_items->{$key}->{due_date} = format_date($item->{onloan}); - $onloan_items->{$key}->{count}++ if $item->{$hbranch}; - $onloan_items->{$key}->{branchname} = $item->{branchname}; - $onloan_items->{$key}->{location} = $shelflocations->{ $item->{location} }; - $onloan_items->{$key}->{itemcallnumber} = $item->{itemcallnumber}; - $onloan_items->{$key}->{description} = $item->{description}; - $onloan_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} ); + my $key = $prefix . $item->{onloan} . $item->{barcode}; + $onloan_items->{$key}->{due_date} = $item->{onloan}; + $onloan_items->{$key}->{count}++ if $item->{$hbranch}; + $onloan_items->{$key}->{branchname} = $item->{branchname}; + $onloan_items->{$key}->{location} = $shelflocations->{ $item->{location} }; + $onloan_items->{$key}->{itemcallnumber} = $item->{itemcallnumber}; + $onloan_items->{$key}->{description} = $item->{description}; + $onloan_items->{$key}->{imageurl} = + getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $item->{itype} }->{imageurl} ); + # if something's checked out and lost, mark it as 'long overdue' if ( $item->{itemlost} ) { - $onloan_items->{$prefix}->{longoverdue}++; + $onloan_items->{$key}->{longoverdue}++; $longoverdue_count++; - } else { # can place holds as long as item isn't lost + } + else { # can place holds as long as item isn't lost $can_place_holds = 1; } } @@ -2124,6 +2126,8 @@ sub searchResults { # items not on loan, but still unavailable ( lost, withdrawn, damaged ) else { + $item->{notforloan}=1 if !$item->{notforloan} && $itemtypes{ C4::Context->preference("item-level_itypes")? $item->{itype}: $oldbiblio->{itemtype} }->{notforloan}; + # item is on order if ( $item->{notforloan} < 0 ) { $ordered_count++; @@ -2142,7 +2146,8 @@ sub searchResults { || $item->{itemlost} || $item->{damaged} || $item->{notforloan} - || $items_count > 20) { + || ( C4::Context->preference('MaxSearchResultsItemsPerRecordStatusCheck') + && $items_count > C4::Context->preference('MaxSearchResultsItemsPerRecordStatusCheck') ) ) { # A couple heuristics to limit how many times # we query the database for item transfer information, sacrificing @@ -2157,7 +2162,7 @@ sub searchResults { # should map transit status to record indexed in Zebra. # ($transfertwhen, $transfertfrom, $transfertto) = C4::Circulation::GetTransfers($item->{itemnumber}); - $reservestatus = C4::Reserves::GetReserveStatus( $item->{itemnumber}, $oldbiblio->{biblionumber} ); + $reservestatus = C4::Reserves::GetReserveStatus( $item->{itemnumber} ); } # item is withdrawn, lost, damaged, not for loan, reserved or in transit @@ -2196,21 +2201,21 @@ sub searchResults { $other_items->{$key}->{intransit} = ( $transfertwhen ne '' ) ? 1 : 0; $other_items->{$key}->{onhold} = ($reservestatus) ? 1 : 0; $other_items->{$key}->{notforloan} = GetAuthorisedValueDesc('','',$item->{notforloan},'','',$notforloan_authorised_value) if $notforloan_authorised_value and $item->{notforloan}; - $other_items->{$key}->{count}++ if $item->{$hbranch}; - $other_items->{$key}->{location} = $shelflocations->{ $item->{location} }; - $other_items->{$key}->{description} = $item->{description}; - $other_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} ); + $other_items->{$key}->{count}++ if $item->{$hbranch}; + $other_items->{$key}->{location} = $shelflocations->{ $item->{location} }; + $other_items->{$key}->{description} = $item->{description}; + $other_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $item->{itype} }->{imageurl} ); } # item is available else { $can_place_holds = 1; $available_count++; - $available_items->{$prefix}->{count}++ if $item->{$hbranch}; - foreach (qw(branchname itemcallnumber description)) { - $available_items->{$prefix}->{$_} = $item->{$_}; - } - $available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} }; - $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} ); + $available_items->{$prefix}->{count}++ if $item->{$hbranch}; + foreach (qw(branchname itemcallnumber description)) { + $available_items->{$prefix}->{$_} = $item->{$_}; + } + $available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} }; + $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $item->{itype} }->{imageurl} ); } } } # notforloan, item level and biblioitem level @@ -2235,12 +2240,9 @@ sub searchResults { } # XSLT processing of some stuff - SetUTF8Flag($marcrecord); - warn $marcrecord->as_formatted if $DEBUG; - my $interface = $search_context eq 'opac' ? 'OPAC' : ''; - if (!$scan && C4::Context->preference($interface . "XSLTResultsDisplay")) { - $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, $interface."XSLTResultsDisplay", 1, \@hiddenitems); - # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs + # we fetched the sysprefs already before the loop through all retrieved record! + if (!$scan && $xslfile) { + $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, $xslsyspref, 1, \@hiddenitems, $sysxml, $xslfile, $lang); } # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either @@ -2250,7 +2252,6 @@ sub searchResults { } } $oldbiblio->{norequests} = 1 unless $can_place_holds; - $oldbiblio->{itemsplural} = 1 if $items_count > 1; $oldbiblio->{items_count} = $items_count; $oldbiblio->{available_items_loop} = \@available_items_loop; $oldbiblio->{onloan_items_loop} = \@onloan_items_loop; @@ -2297,101 +2298,14 @@ sub searchResults { $oldbiblio->{'alternateholdings_count'} = $alternateholdingscount; } + $oldbiblio->{biblio_object} = Koha::Biblios->find( $oldbiblio->{biblionumber} ); + push( @newresults, $oldbiblio ); } return @newresults; } -=head2 SearchAcquisitions - Search for acquisitions -=cut - -sub SearchAcquisitions{ - my ($datebegin, $dateend, $itemtypes,$criteria, $orderby) = @_; - - my $dbh=C4::Context->dbh; - # Variable initialization - my $str=qq| - SELECT marcxml - FROM biblio - LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber - LEFT JOIN items ON items.biblionumber=biblio.biblionumber - WHERE dateaccessioned BETWEEN ? AND ? - |; - - my (@params,@loopcriteria); - - push @params, $datebegin->output("iso"); - push @params, $dateend->output("iso"); - - if (scalar(@$itemtypes)>0 and $criteria ne "itemtype" ){ - if(C4::Context->preference("item-level_itypes")){ - $str .= "AND items.itype IN (?".( ',?' x scalar @$itemtypes - 1 ).") "; - }else{ - $str .= "AND biblioitems.itemtype IN (?".( ',?' x scalar @$itemtypes - 1 ).") "; - } - push @params, @$itemtypes; - } - - if ($criteria =~/itemtype/){ - if(C4::Context->preference("item-level_itypes")){ - $str .= "AND items.itype=? "; - }else{ - $str .= "AND biblioitems.itemtype=? "; - } - - if(scalar(@$itemtypes) == 0){ - my $itypes = GetItemTypes(); - for my $key (keys %$itypes){ - push @$itemtypes, $key; - } - } - - @loopcriteria= @$itemtypes; - }elsif ($criteria=~/itemcallnumber/){ - $str .= "AND (items.itemcallnumber LIKE CONCAT(?,'%') - OR items.itemcallnumber is NULL - OR items.itemcallnumber = '')"; - - @loopcriteria = ("AA".."ZZ", "") unless (scalar(@loopcriteria)>0); - }else { - $str .= "AND biblio.title LIKE CONCAT(?,'%') "; - @loopcriteria = ("A".."z") unless (scalar(@loopcriteria)>0); - } - - if ($orderby =~ /date_desc/){ - $str.=" ORDER BY dateaccessioned DESC"; - } else { - $str.=" ORDER BY title"; - } - - my $qdataacquisitions=$dbh->prepare($str); - - my @loopacquisitions; - foreach my $value(@loopcriteria){ - push @params,$value; - my %cell; - $cell{"title"}=$value; - $cell{"titlecode"}=$value; - - eval{$qdataacquisitions->execute(@params);}; - - if ($@){ warn "recentacquisitions Error :$@";} - else { - my @loopdata; - while (my $data=$qdataacquisitions->fetchrow_hashref){ - push @loopdata, {"summary"=>GetBiblioSummary( $data->{'marcxml'} ) }; - } - $cell{"loopdata"}=\@loopdata; - } - push @loopacquisitions,\%cell if (scalar(@{$cell{loopdata}})>0); - pop @params; - } - $qdataacquisitions->finish; - return \@loopacquisitions; -} - =head2 enabled_staff_search_views %hash = enabled_staff_search_views() @@ -2425,13 +2339,6 @@ sub enabled_staff_search_views ); } -sub PurgeSearchHistory{ - my ($pSearchhistory)=@_; - my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare("DELETE FROM search_history WHERE time < DATE_SUB( NOW(), INTERVAL ? DAY )"); - $sth->execute($pSearchhistory) or die $dbh->errstr; -} - =head2 z3950_search_args $arrayref = z3950_search_args($matchpoints) @@ -2582,7 +2489,7 @@ sub _ZOOM_event_loop { =head2 new_record_from_zebra -Given raw data from a Zebra result set, return a MARC::Record object +Given raw data from a searchengine result set, return a MARC::Record object This helper function is needed to take into account all the involved system preferences and configuration variables to properly create the @@ -2591,6 +2498,9 @@ MARC::Record object. If we are using GRS-1, then the raw data we get from Zebra should be USMARC data. If we are using DOM, then it has to be MARCXML. +If we are using elasticsearch, it'll already be a MARC::Record and this +function needs a new name. + =cut sub new_record_from_zebra { @@ -2598,6 +2508,10 @@ sub new_record_from_zebra { my $server = shift; my $raw_data = shift; # Set the default indexing modes + my $search_engine = C4::Context->preference("SearchEngine"); + if ($search_engine eq 'Elasticsearch') { + return ref $raw_data eq 'MARC::Record' ? $raw_data : MARC::Record->new_from_xml( $raw_data, 'UTF-8' ); + } my $index_mode = ( $server eq 'biblioserver' ) ? C4::Context->config('zebra_bib_index_mode') // 'dom' : C4::Context->config('zebra_auth_index_mode') // 'dom';