[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Koha-cvs] koha/C4 Search.pm [dev_week]
From: |
Joshua Ferraro |
Subject: |
[Koha-cvs] koha/C4 Search.pm [dev_week] |
Date: |
Tue, 19 Sep 2006 04:44:35 +0000 |
CVSROOT: /sources/koha
Module name: koha
Branch: dev_week
Changes by: Joshua Ferraro <kados> 06/09/19 04:44:34
Modified files:
C4 : Search.pm
Log message:
Cleanup of some unused functions (there are many more unused
functions!!)
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/koha/C4/Search.pm?cvsroot=koha&only_with_tag=dev_week&r1=1.99.2.11.2.22&r2=1.99.2.11.2.23
Patches:
Index: Search.pm
===================================================================
RCS file: /sources/koha/koha/C4/Search.pm,v
retrieving revision 1.99.2.11.2.22
retrieving revision 1.99.2.11.2.23
diff -u -b -r1.99.2.11.2.22 -r1.99.2.11.2.23
--- Search.pm 10 Aug 2006 02:10:21 -0000 1.99.2.11.2.22
+++ Search.pm 19 Sep 2006 04:44:34 -0000 1.99.2.11.2.23
@@ -24,19 +24,22 @@
use C4::Reserves2;
use C4::Biblio;
use C4::Koha;
+use C4::Record;
use Date::Calc;
use MARC::File::XML;
use MARC::File::USMARC;
use MARC::Record;
+use Lingua::Stem;
+
# FIXME - C4::Search uses C4::Reserves2, which uses C4::Search.
# So Perl complains that all of the functions here get redefined.
-use C4::Date;
+#use C4::Date;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
# set the version for version checking
-$VERSION = do { my @v = '$Revision: 1.99.2.11.2.22 $' =~ /\d+/g;
+$VERSION = do { my @v = '$Revision: 1.99.2.11.2.23 $' =~ /\d+/g;
shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
=head1 NAME
@@ -45,38 +48,40 @@
=head1 SYNOPSIS
- use C4::Search;
-
- my ($count, @results) = catalogsearch($env, $type, $search, $num, $offset);
+see opac/search for example of usage
=head1 DESCRIPTION
-This module provides the searching facilities for the Koha catalog and
-other databases.
-
-C<&catalogsearch> is a front end to all the other searches. Depending
-on what is passed to it, it calls the appropriate search function.
+This module provides the searching facilities for the Koha bibliographic,
+SQL, and other databases.
=head1 FUNCTIONS
-=over 2
-
=cut
@ISA = qw(Exporter);
@EXPORT = qw(
-&CatSearch &BornameSearch &ItemInfo &KeywordSearch &subsearch
-&itemdata &bibdata &GetItems &borrdata &itemnodata &itemcount
-&borrdata2 &borrdata3 &NewBorrowerNumber &bibitemdata &borrissues
+&CatSearch
+
+&BornameSearch &ItemInfo &KeywordSearch
+
+&subsearch
+
+&itemdata &bibdata
+
+&GetItems &borrdata &itemnodata &itemcount &itemcount2
+&borrdata2 &borrdata3
+
+&NewBorrowerNumber &bibitemdata &borrissues
&getboracctrecord &ItemType &itemissues &subject &subtitle
&addauthor &bibitems &barcodes &findguarantees &allissues
-&findseealso &findguarantor &getwebsites &getwebbiblioitems &itemcount2
&FindDuplicate
-&isbnsearch &getbranchname &getborrowercategory &getborrowercategoryinfo
+&findseealso &findguarantor
-&searchZOOM &catalogsearch &catalogsearch3 &CatSearch3 &catalogsearch4
&searchResults
+&getwebsites &getwebbiblioitems &FindDuplicate
+&isbnsearch &getbranchname &getborrowercategory &getborrowercategoryinfo
-&getRecords &buildQuery
+&searchZOOM &searchResults &getRecords &buildQuery
&getMARCnotes &getMARCsubjects &getMARCurls);
# make all your functions, whether exported or not;
@@ -315,7 +320,7 @@
$lineCN{holdingbranch} = $item->{holdingbranch};
$lineCN{itemcallnumber} = $item->{itemcallnumber};
$lineCN{location} = $item->{location};
- $lineCN{date_due} = format_date($date_due);
+ $lineCN{date_due} = $date_due; #format_date($date_due);
#$lineCN{notforloan} = $notforloanstatus{$line->{notforloan}} if
($line->{notforloan}); # setting not forloan if itemtype is not for loan
#$lineCN{notforloan} = $notforloanstatus{$item->{notforloan}} if
($item->{notforloan}); # setting not forloan it this item is not for loan
$notforloan=0 unless ($item->{notforloan} or $item->{wthdrawn} or
$item->{itemlost});
@@ -343,7 +348,7 @@
$newline{CN} = address@hidden;
$newline{'even'} = 1 if $#finalresult % 2 == 0;
$newline{'odd'} = 1 if $#finalresult % 2 == 1;
- $newline{'timestamp'} = format_date($newline{timestamp});
+ #$newline{'timestamp'} = format_date($newline{timestamp});
@CNresults = ();
push @finalresult, \%newline;
$totalitems=0;
@@ -418,1398 +423,231 @@
}
-sub catalogsearch3 {
- my ($search,$num,$offset) = @_;
- my $dbh = C4::Context->dbh;
- my ($count,@results);
-
- if ($search->{'itemnumber'} ne '' || $search->{'isbn'} ne ''||
$search->{'biblionumber'} ne ''){
- ($count,@results) = CatSearch3('precise',$search,$num,$offset);
- } elsif ($search->{'keyword'} ne ''){
- ($count,@results) = CatSearch3('keyword',$search,$num,$offset);
- } elsif ($search->{'recently_items'} ne '') {
- ($count,@results) =
CatSearch3('recently_items',$search,$num,$offset);
- } else {
- ($count,@results) = CatSearch3('loose',$search,$num,$offset);
+sub FindDuplicate {
+ my ($record)address@hidden;
+my $dbh=C4::Context->dbh;
+ my $result = MARCmarc2koha($dbh,$record,'');
+ my $sth;
+ my $query;
+ my $search;
+ my $type;
+ my ($biblionumber,$bibid,$title);
+ # search duplicate on ISBN, easy and fast..
+$search->{'avoidquerylog'}=1;
+ if ($result->{isbn}) {
+ $type="precise";
+###Temporary fix for ISBN
+my $isbn=$result->{isbn};
+$isbn=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\!|\'|,|\-|\"|\(|\)|\[|\]|\{|\}|\/)//g;
+ $search->{'isbn'}=$isbn;
+ }else{
+$result->{title}=~s /\\//g;
+$result->{title}=~s /\"//g;
+ $type="loose";
+ $search->{'field_name1'}="title";
+ $search->{'field_value1'}=$result->{title};
+ $search->{'ttype1'}="exact";
+ $search->{'atype1'}="start";
}
+ my ($total,@result)=CatSearch4($type,$search,1,0);
+ return $result[0]->{'biblionumber'},
$result[0]->{'biblionumber'},$result[0]->{'title'} if ($total);
-
- return ($count,@results);
}
+=item KeywordSearch
-sub CatSearch3 {
-
- my ($type,$search,$num,$offset)address@hidden;
- my $dbh = C4::Context->dbh;
- my $query = ''; #to make the query statement
- my $count_query = ''; #to count total results
- my @params = (); #to collect the params
- my @results; #to retrieve the results
-
- # 1) do a search by barcode or isbn
- if ($type eq 'precise') {
-
- if ($search->{'itemnumber'} ne ''){
- $query = "SELECT biblionumber FROM items WHERE (barcode
= ?)";
- push @params, $search->{'itemnumber'};
+ $search = { "keyword" => "One or more keywords",
+ "class" => "VID|CD", # Limit search to fiction and CDs
+ "dewey" => "813",
+ };
+ ($count, @results) = &KeywordSearch($env, $type, $search, $num, $offset);
- } elsif ($search->{'isbn'} ne '') {
- $query = "SELECT biblionumber FROM biblioitems WHERE
(isbn like ?)";
- push @params, $search->{'isbn'};
- }else {
- $query = "SELECT biblionumber FROM biblioitems WHERE
(biblionumber = ?)";
- push @params, $search->{'biblionumber'};
- }
-
- #add branch condition
- if ($search->{'branch'} ne '') {
- $query.= " AND ( holdingbranch like ? ) ";
- my $keys = $search->{'branch'};
- push @params, $keys;
- }
-
- # 2) do a search by keyword
- } elsif ($type eq 'keyword') {
- my $keys = $search->{'keyword'};
- my @words = split / /, $keys;
-
- #parse the keywords
- my $keyword;
- if ($search->{'ttype'} eq 'exact') {
- for (my $i = 0; $i < @words ;$i++) {
- if ($i + 1 == @words) {
- $words[$i] = '+' . $words[$i] . '*';
- } else {
- $words[$i] = '+' . $words[$i];
- }
- }
- } else {
- for (my $i = 0; $i < @words ;$i++) {
- $words[$i] = $words[$i] . '*';
- }
- }
- $keyword = join " ", @words;
+C<&KeywordSearch> searches the catalog by keyword: given a string
+(C<$search-E<gt>{"keyword"}> consisting of a space-separated list of
+keywords, it looks for books that contain any of those keywords in any
+of a number of places.
- #Builds the SQL
- $query = "(SELECT DISTINCT B.biblionumber AS biblionumber ,(
MATCH
(title,seriestitle,unititle,B.author,subject,publishercode,itemcallnumber)
AGAINST(? in BOOLEAN MODE) ) as Relevance
- FROM biblio AS B
- LEFT JOIN biblioitems AS BI ON
(B.biblionumber = BI.biblionumber)
- LEFT JOIN items AS I ON
(BI.biblionumber = I.biblionumber)
- LEFT JOIN additionalauthors AA1
ON (B.biblionumber = AA1.biblionumber)
- LEFT JOIN bibliosubject AS BS1
ON (B.biblionumber = BS1.biblionumber)
- LEFT JOIN bibliosubtitle AS
BSU1 ON (B.biblionumber = BSU1.biblionumber)
- where MATCH
(title,seriestitle,unititle,B.author,subject,publishercode,itemcallnumber)
AGAINST (? IN BOOLEAN MODE) ";
-
- push @params,$keyword;
- push @params,$keyword;
- #search by class
- if ($search->{'class'} ne '') {
- $query .= " AND ( itemtype = ? ) ";
- push @params, $search->{'class'};
- }
- #search by branch
- if ($search->{'branch'} ne '') {
- $query .= " AND ( items.holdingbranch like ? ) ";
- push @params, $search->{'branch'};
- }
- if ($search->{'stack'} ne '') {
- $query .= " AND ( items.stack = ? ) ";
- push @params, $search->{'stack'};
- }
- #search by publication year
- if ($search->{'date_from'} ne '') {
- $query .= " AND ( biblioitems.publicationyear >= ?) ";
- push @params, $search->{'date_from'};
- if ($search->{'date_to'} ne '') {
- $query .= " AND ( biblioitems.publicationyear
<= ?) ";
- push @params, $search->{'date_to'};
+C<&KeywordSearch> looks for keywords in the book title (and subtitle),
+series name, notes (both C<biblio.notes> and C<biblioitems.notes>),
+and subjects.
- }
- }
- $query .= ")";
+C<$search-E<gt>{"class"}> can be set to a C<|> (pipe)-separated list of
+item class codes (e.g., "F" for fiction, "JNF" for junior nonfiction,
+etc.). In this case, the search will be restricted to just those
+classes.
+If C<$search-E<gt>{"class"}> is not specified, you may specify
+C<$search-E<gt>{"dewey"}>. This will restrict the search to that
+particular Dewey Decimal Classification category. Setting
+C<$search-E<gt>{"dewey"}> to "513" will return books about arithmetic,
+whereas setting it to "5" will return all books with Dewey code 5I<xx>
+(Science and Mathematics).
+C<$env> and C<$type> are ignored.
+C<$offset> and C<$num> specify the subset of results to return.
+C<$num> specifies the number of results to return, and C<$offset> is
+the number of the first result. Thus, setting C<$offset> to 100 and
+C<$num> to 5 will return results 100 through 104 inclusive.
- # 3) search the items acquired recently (in the last $search->{'range'}
days)
- } elsif ($type eq 'recently_items') {
- my $keys;
- if ($search->{'range'}) {
- $keys = $search->{'range'};
- } else {
- $keys = 30;
- }
- $query = "SELECT B.biblionumber FROM biblio AS B
- LEFT JOIN biblioitems
AS BI ON (B.biblionumber = BI.biblionumber)
+=cut
+#'
+sub KeywordSearch {
+ my ($env,$type,$search,$num,$offset)address@hidden;
+ my $dbh = C4::Context->dbh;
+ $search->{'keyword'}=~ s/ +$//;
+ my @key=split(' ',$search->{'keyword'});
+ # FIXME - Naive users might enter comma-separated
+ # words, e.g., "training, animal". Ought to cope with
+ # this.
+ my address@hidden;
+ my $i=1;
+ my %biblionumbers; # Set of biblionumbers returned by the
+ # various searches.
- WHERE
- (TO_DAYS( NOW( ) ) -
TO_DAYS( B.timestamp ))<?";
- #search by class
- push @params, $keys;
- if ($search->{'class'} ne '') {
- $query .= " AND ( BI.itemtype = ? ) ";
- push @params, $search->{'class'};
- }
- $query.= " ORDER BY title ";
+ # FIXME - Ought to filter the stopwords out of the list of keywords.
+ # @key = map { !defined($stopwords{$_}) } @key;
- # 4) do a loose search
- } else {
+ # FIXME - The way this code is currently set up, it looks for all of
+ # the keywords first in (title, notes, seriestitle), then in the
+ # subtitle, then in the subject. Thus, if you look for keywords
+ # "science fiction", this search won't find a book with
+ # title = "How to write fiction"
+ # subtitle = "A science-based approach"
+ # Is this the desired effect? If not, then the first SQL query
+ # should look in the biblio, subtitle, and subject tables all at
+ # once. The way the first query is built can accomodate this easily.
- my ($condition1, $condition2, $condition3) = ('','','');
- my $count_params = 0;
+ # Look for keywords in table 'biblio'.
+ # Build an SQL query that finds each of the keywords in any of the
+ # title, biblio.notes, or seriestitle. To do this, we'll build up an
+ # array of clauses, one for each keyword.
+ my $query; # The SQL query
+ my @clauses = (); # The search clauses
+ my @bind = (); # The term bindings
- #search_field 1
- if ($search->{'field_name1'} eq 'all') {
- $condition1.= " ( MATCH
(title,seriestitle,unititle,B.author,subject,publishercode,itemcallnumber)
AGAINST(? in BOOLEAN MODE) ) ";
-
- $count_params = 1;
- } elsif ($search->{'field_name1'} eq 'author') {
- $condition1.= " ( MATCH (B.author) AGAINST(?
in BOOLEAN MODE) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name1'} eq 'title') {
- $condition1.= " ( MATCH
(title,seriestitle,unititle) AGAINST(? in BOOLEAN MODE ) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name1'} eq 'subject') {
- $condition1.= " ( ( MATCH (subject) AGAINST(?
in BOOLEAN MODE) ) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name1'} eq 'publisher') {
- $condition1.= " ( MATCH (publishercode)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- } elsif ($search->{'field_name1'} eq 'publicationyear')
{
- $condition1.= " ( MATCH (publicationyear)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- } elsif ($search->{'field_name1'} eq 'callno') {
- $condition1.= " ( MATCH (itemcallnumber)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- }
-
- if ($search->{'ttype1'} eq 'exact') {
- push
@params,"\"".$search->{'field_value1'}."\"";
- push @params,
"\"".$search->{'field_value1'}."\"";
- } else {
- my $keys = $search->{'field_value1'};
- my @words = split / /, $keys;
- #parse the keywords
- my $keyword;
- for (my $i = 0; $i < @words
;$i++) {
- $words[$i] = '+'. $words[$i] .
'*';
- }
- $keyword = join " ", @words;
- push @params, $keyword;
- push @params, $keyword;
+ $query = <<EOT; # Beginning of the query
+ SELECT biblionumber
+ FROM biblio
+ WHERE
+EOT
+ foreach my $keyword (@key)
+ {
+ my @subclauses = (); # Subclauses, one for each field we're
+ # searching on
+ # For each field we're searching on, create a subclause that'll
+ # match the current keyword in the current field.
+ foreach my $field (qw(title notes seriestitle author))
+ {
+ push @subclauses,
+ "$field LIKE ? OR $field LIKE ?";
+ push(@bind,"\Q$keyword\E%","% \Q$keyword\E%");
}
+ # (Yes, this could have been done as
+ # @subclauses = map {...} qw(field1 field2 ...)
+ # )but I think this way is more readable.
- $query = " SELECT DISTINCT B.biblionumber AS
biblionumber ,$condition1 as Relevance
- FROM biblio AS B
- LEFT JOIN biblioitems AS BI ON
(B.biblionumber = BI.biblionumber)
- LEFT JOIN items AS I ON
(BI.biblionumber = I.biblionumber)
- LEFT JOIN additionalauthors AA1
ON (B.biblionumber = AA1.biblionumber)
- LEFT JOIN bibliosubject AS BS1
ON (B.biblionumber = BS1.biblionumber)
- LEFT JOIN bibliosubtitle AS
BSU1 ON (B.biblionumber = BSU1.biblionumber) ";
-
-
- #search_field 2
- if ( ($search->{'field_value1'}) &&
($search->{'field_value2'}) ) {
- if ($search->{'field_name2'} eq 'all') {
- $condition2.= " MATCH
(title,seriestitle,unititle,B.author,subject,publishercode,itemcallnumber)
AGAINST( ? in BOOLEAN MODE) ) ";
-
- $count_params = 1;
- } elsif ($search->{'field_name2'} eq 'author') {
- $condition2.= " MATCH (B.author,AA1.author)
AGAINST( ? in BOOLEAN MODE) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name2'} eq 'title') {
- $condition2.= " MATCH
(title,seriestitle,unititle) AGAINST( ? in BOOLEAN MODE ) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name2'} eq 'subject') {
- $condition2.= " MATCH (subject) AGAINST(? in
BOOLEAN MODE) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name2'} eq 'publisher') {
- $condition2.= " MATCH (publishercode) AGAINST(?
in BOOLEAN MODE )) ";
- $count_params = 1;
- } elsif ($search->{'field_name2'} eq 'publicationyear')
{
- $condition2.= " MATCH (publicationyear)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- } elsif ($search->{'field_name2'} eq 'callno') {
- $condition2.= " MATCH (itemcallnumber)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- }
- if ($search->{'op1'} eq "not"){
- $search->{'op1'}="and (not ";
- }else{
- $search->{'op1'}.=" (";
+ # Construct the current clause by joining the subclauses.
+ push @clauses, "(" . join(")\n\tOR (", @subclauses) . ")";
}
+ # Now join all of the clauses together and append to the query.
+ $query .= "(" . join(")\nAND (", @clauses) . ")";
- if ($search->{'ttype2'} eq 'exact') {
- push @params,
"\"".$search->{'field_value2'}."\"";
- } else {
- my $keys = $search->{'field_value2'};
- my @words = split / /, $keys;
- #parse the keywords
- my $keyword;
- for (my $i = 0; $i < @words
;$i++) {
- $words[$i] = "+". $words[$i] .
'*';
- }
- $keyword = join " ", @words;
- push @params, $keyword;
+ # FIXME - Perhaps use $sth->bind_columns() ? Documented as the most
+ # efficient way to fetch data.
+ my $sth=$dbh->prepare($query);
+ $sth->execute(@bind);
+ while (my @res = $sth->fetchrow_array) {
+ for (@res)
+ {
+ $biblionumbers{$_} = 1; # Add these results to the set
}
-
}
+ $sth->finish;
- #search_field 3
- if ( ($search->{'field_value2'}) &&
($search->{'field_value3'}) ) {
-
- if ($search->{'field_name3'} eq 'all') {
- $condition3.= " MATCH
(title,seriestitle,unititle,B.author,subject,publishercode,itemcallnumber)
AGAINST(? in BOOLEAN MODE ) ) ";
-
- $count_params = 1;
- } elsif ($search->{'field_name3'} eq 'author') {
- $condition3.= " MATCH (B.author,AA1.author)
AGAINST(? in BOOLEAN MODE) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name3'} eq 'title') {
- $condition3.= " MATCH
(title,seriestitle,unititle) AGAINST(? in BOOLEAN MODE) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name3'} eq 'subject') {
- $condition3.= " MATCH (subject) AGAINST(? in
BOOLEAN MODE ) ) ";
- $count_params = 1;
- } elsif ($search->{'field_name3'} eq 'publisher') {
- $condition3.= " MATCH (publishercode)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- } elsif ($search->{'field_name3'} eq 'publicationyear')
{
- $condition3.= " MATCH (publicationyear)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- } elsif ($search->{'field_name3'} eq 'callno') {
- $condition3.= " MATCH (itemcallnumber)
AGAINST(? in BOOLEAN MODE )) ";
- $count_params = 1;
- }
- if ($search->{'op2'} eq "not"){
- $search->{'op2'}="and (not ";
- }else{
- $search->{'op2'}.=" (";
- }
- if ($search->{'ttype3'} eq 'exact') {
- push @params,
"\"".$search->{'field_value3'}."\"";
- } else {
- my $keys = $search->{'field_value3'};
- my @words = split / /, $keys;
- #parse the keywords
- my $keyword;
+ # Now look for keywords in the 'bibliosubtitle' table.
- for (my $i = 0; $i < @words
;$i++) {
- $words[$i] = "+". $words[$i] .
'*';
- }
- $keyword = join " ", @words;
- push @params, $keyword;
- }
+ # Again, we build a list of clauses from the keywords.
+ @clauses = ();
+ @bind = ();
+ $query = "SELECT biblionumber FROM bibliosubtitle WHERE ";
+ foreach my $keyword (@key)
+ {
+ push @clauses,
+ "subtitle LIKE ? OR subtitle like ?";
+ push(@bind,"\Q$keyword\E%","% \Q$keyword\E%");
}
+ $query .= "(" . join(") AND (", @clauses) . ")";
- $query.= " WHERE ";
- if (($condition1 ne '') && ($condition2 ne '') &&
($condition3 ne '')) {
- if ($search->{'op1'} eq $search->{'op2'}) {
- $query.= " ( $condition1
$search->{'op1'} $condition2 $search->{'op2'} $condition3 ) ";
- } elsif ( $search->{'op1'} eq "and (" ) {
- $query.= " ( $condition1
$search->{'op1'} ( $condition2 $search->{'op2'} $condition3 ) ) ";
- } else {
- $query.= " ( ( $condition1
$search->{'op1'} $condition2 ) $search->{'op2'} $condition3 ) ";
+ $sth=$dbh->prepare($query);
+ $sth->execute(@bind);
+ while (my @res = $sth->fetchrow_array) {
+ for (@res)
+ {
+ $biblionumbers{$_} = 1; # Add these results to the set
}
- } elsif ( ($condition1 ne '') && ($condition2 ne '') ) {
- $query.= " ( $condition1 $search->{'op1'}
$condition2 ) ";
- } else {
- $query.= " ( $condition1 ) ";
}
+ $sth->finish;
- #search by class
- if ($search->{'class'} ne ''){
- $query.= " AND ( itemtype = ? ) ";
- my $keys = $search->{'class'};
- push @params, $search->{'class'};
- }
- #search by branch
- if ($search->{'branch'} ne '') {
- $query.= " AND I.holdingbranch like ? ";
- my $keys = $search->{'branch'};
- push @params, $keys, $keys;
- }
- #search by publication year
- if ($search->{'date_from'} ne '') {
- $query .= " AND ( BI.publicationyear >= ?) ";
- push @params, $search->{'date_from'};
- if ($search->{'date_to'} ne '') {
- $query .= " AND (
BI.publicationyear <= ?) ";
- push @params, $search->{'date_to'};
+ # Look for the keywords in the notes for individual items
+ # ('biblioitems.notes')
+ # Again, we build a list of clauses from the keywords.
+ @clauses = ();
+ @bind = ();
+ $query = "SELECT biblionumber FROM biblioitems WHERE ";
+ foreach my $keyword (@key)
+ {
+ push @clauses,
+ "notes LIKE ? OR notes like ?";
+ push(@bind,"\Q$keyword\E%","% \Q$keyword\E%");
}
- }
- if ($search->{'order'} eq "1=1003 i<"){
- $query.= " ORDER BY b.author ";
- }elsif ($search->{'order'} ge "1=9 i<"){
- $query.= " ORDER BY lcsort ";
- }elsif ($search->{'order'} eq "1=4 i<"){
- $query.= " ORDER BY title ";
- }else{
- $query.=" ORDER BY Relevance DESC";
+ $query .= "(" . join(") AND (", @clauses) . ")";
+
+ $sth=$dbh->prepare($query);
+ $sth->execute(@bind);
+ while (my @res = $sth->fetchrow_array) {
+ for (@res)
+ {
+ $biblionumbers{$_} = 1; # Add these results to the set
}
}
+ $sth->finish;
-#warn "$query,@params,";
- $count_query = $query;
- warn "QUERY:".$count_query;
- #execute the query and returns just the results between $num and $num +
$offset
- my $limit = $num + $offset;
- my $startfrom = $offset;
- my $sth = $dbh->prepare($query);
-
- $sth->execute(@params);
-
- my $i = 0;
-#Build brancnames hash
-#find branchname
-#get branch information.....
-my %branches;
- my $bsth=$dbh->prepare("SELECT branchcode,branchname FROM
branches");
- $bsth->execute();
- while (my $bdata=$bsth->fetchrow_hashref){
- $branches{$bdata->{'branchcode'}}=
$bdata->{'branchname'};
-
- }
+ # Look for keywords in the 'bibliosubject' table.
-#Building shelving hash
-my %shelves;
-#find shelvingname
-my $stackstatus = $dbh->prepare('select authorised_value from
marc_subfield_structure where kohafield="items.stack"');
- $stackstatus->execute;
+ # FIXME - The other queries look for words in the desired field that
+ # begin with the individual keywords the user entered. This one
+ # searches for the literal string the user entered. Is this the
+ # desired effect?
+ # Note in particular that spaces are retained: if the user typed
+ # science fiction
+ # (with two spaces), this won't find the subject "science fiction"
+ # (one space). Likewise, a search for "%" will return absolutely
+ # everything.
+ # If this isn't the desired effect, see the previous searches for
+ # how to do it.
- my ($authorised_valuecode) = $stackstatus->fetchrow;
- if ($authorised_valuecode) {
- $stackstatus = $dbh->prepare("select
lib,authorised_value from authorised_values where category=? ");
- $stackstatus->execute($authorised_valuecode);
+ $sth=$dbh->prepare("Select biblionumber from bibliosubject where subject
+ like ? group by biblionumber");
+ $sth->execute("%$search->{'keyword'}%");
- while (my $lib = $stackstatus->fetchrow_hashref){
- $shelves{$lib->{'authorised_value'}} = $lib->{'lib'};
- }
+ while (my @res = $sth->fetchrow_array) {
+ for (@res)
+ {
+ $biblionumbers{$_} = 1; # Add these results to the set
}
-
-#search item field code
- my $sth3 =
- $dbh->prepare(
- "select tagfield from marc_subfield_structure where kohafield like
'items.itemnumber'"
- );
- $sth3->execute;
- my ($itemtag) = $sth3->fetchrow;
-## 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 ($tagfield,$tagsubfield) =
&MARCfind_marc_from_kohafield($dbh,"items.".$column,"");
- $subfieldstosearch{$column}=$tagsubfield;
}
-my $toggle;
-my $even;
-#proccess just the results to show
- while (my( $data,$rel) = $sth->fetchrow) {
- if (($i >= $startfrom) && ($i < $limit)) {
+ $sth->finish;
- my $marcrecord=MARCgetbiblio($dbh,$data);
- my $oldbiblio=MARCmarc2koha($dbh,$marcrecord,'');
+ my $i2=0;
+ my $i3=0;
+ my $i4=0;
-
- &add_html_bold_fields($type, $oldbiblio, $search);
-if ($i % 2) {
- $toggle="#ffffcc";
- } else {
- $toggle="white";
- }
- $oldbiblio->{'toggle'}=$toggle;
-
-
-
- my @fields = $marcrecord->field($itemtag);
-my @items;
- my $item;
-my %counts;
-$counts{'total'}=0;
-
-#
-##Loop for each item field
- foreach my $field (@fields) {
- foreach my $code ( keys %subfieldstosearch ) {
-
-$item->{$code}=$field->subfield($subfieldstosearch{$code});
-}
-
-my $status;
-
-$item->{'branchname'}=$branches{$item->{'holdingbranch'}};
-$item->{'shelves'}=$shelves{$item->{stack}};
-$status="Lost" if ($item->{'itemlost'}>0);
-$status="Withdrawn" if ($item->{'wthdrawn'}>0) ;
-if ($search->{'from'} eq "intranet"){
-$search->{'avoidquerylog'}=1;
-$status="Due:".format_date($item->{'onloan'}) if ($item->{'onloan'}>0);
- $status =
$item->{'holdingbranch'}."-".$item->{'stack'}."[".$item->{'itemcallnumber'}."]"
unless defined $status;
-}else{
-$status="On Loan" if ($item->{'onloan'}>0);
- $status = $item->{'branchname'}."[".$item->{'shelves'}."]" unless defined
$status;
-}
- $counts{$status}++;
-$counts{'total'}++;
-push @items,$item;
-
- }
-
- my $norequests = 1;
- my $noitems = 1;
- if (@items) {
- $noitems = 0;
- foreach my $itm (@items) {
- $norequests = 0 unless $itm->{'itemnotforloan'};
- }
- }
- $oldbiblio->{'noitems'} = $noitems;
- $oldbiblio->{'norequests'} = $norequests;
- $oldbiblio->{'even'} = $even = not $even;
- $oldbiblio->{'itemcount'} = $counts{'total'};
- my $totalitemcounts = 0;
- foreach my $key (keys %counts){
- if ($key ne 'total'){
- $totalitemcounts+= $counts{$key};
-
$oldbiblio->{'locationhash'}->{$key}=$counts{$key};
- }
- }
-
- my ($locationtext, $locationtextonly, $notavailabletext) =
('','','');
- foreach (sort keys %{$oldbiblio->{'locationhash'}}) {
- if ($_ eq 'notavailable') {
- $notavailabletext="Not available";
- my $c=$oldbiblio->{'locationhash'}->{$_};
- $oldbiblio->{'not-available-p'}=$c;
- } else {
- $locationtext.="$_";
- my $c=$oldbiblio->{'locationhash'}->{$_};
- if ($_ eq 'Item Lost') {
- $oldbiblio->{'lost-p'} = $c;
- } elsif ($_ eq 'Withdrawn') {
- $oldbiblio->{'withdrawn-p'} = $c;
- } elsif ($_ eq 'On Loan') {
- $oldbiblio->{'on-loan-p'} = $c;
- } else {
- $locationtextonly.= $_;
- $locationtextonly.= " ($c)<br> " if
$totalitemcounts > 1;
- }
- if ($totalitemcounts>1) {
- $locationtext.=" ($c)<br> ";
- }
- }
- }
- if ($notavailabletext) {
- $locationtext.= $notavailabletext;
- } else {
- $locationtext=~s/, $//;
- }
- $oldbiblio->{'location'} = $locationtext;
- $oldbiblio->{'location-only'} = $locationtextonly;
- $oldbiblio->{'use-location-flags-p'} = 1;
- push @results, $oldbiblio;
-
- }
- $i++;
- }
-
- my $count = $i;
- unless ($search->{'avoidquerylog'}) {
- add_query_line($type, $search, $count);}
- return($count,@results);
-}
-
-sub catalogsearch4 {
- my ($search,$num,$offset) = @_;
- my ($count,@results);
-
- if ($search->{'itemnumber'} ne '' || $search->{'isbn'} ne ''||
$search->{'biblionumber'} ne ''|| $search->{'authnumber'} ne ''){
- ($count,@results) = CatSearch4('precise',$search,$num,$offset);
- } elsif ($search->{'cql'} ne ''){
- if ($search->{'rpn'} ne '') {
- warn "RPN ON";
- ($count,@results) =
CatSearch4('rpn',$search,$num,$offset);
- } else {
- warn "RPN".$search->{'rpn'};
- ($count,@results) = CatSearch4('cql',$search,$num,$offset);
- }
- } elsif ($search->{'keyword'} ne ''){
- ($count,@results) = CatSearch4('keyword',$search,$num,$offset);
- } elsif ($search->{'recently_items'} ne '') {
- ($count,@results) =
CatSearch4('recently_items',$search,$num,$offset);
- } else {
- ($count,@results) = CatSearch4('loose',$search,$num,$offset);
- }
- return ($count,@results);
-}
-
-sub CatSearch4 {
-
- my ($type,$search,$num,$offset)address@hidden;
- my $dbh = C4::Context->dbh;
- my $query = ''; #to make the query statement
- my $count_query = ''; #to count total results
- my @params = (); #to collect the params
- my @results; #to retrieve the results
- my $attr;
- my $attr2;
- my $attr3;
- my $numresults;
- my $marcdata;
- my $toggle;
- my $even=1;
- my $cql;
- my $rpn;
- my $cql_query;
- # 1) do a search by barcode or isbn
- if ($type eq 'cql') {
- $cql=1;
- $cql_query = $search->{'cql'};
- while( my ($k, $v) = each %$search ) {
- warn "key: $k, value: $v.\n";
- }
- warn "QUERY:".$query;
- }
- if ($type eq 'rpn') {
- $rpn=1;
- $cql=1;
- $cql_query = $search->{'cql'}; #but it's really a rpn query
FIXME
- }
- if ($type eq 'precise') {
-
- if ($search->{'itemnumber'} ne '') {
-
- $query = " address@hidden 1=1028 ".
$search->{'itemnumber'};
-
-
- }elsif ($search->{'isbn'} ne ''){
- $query = " address@hidden 1=7 address@hidden 4=1
address@hidden 5=1 "."\"".$search->{'isbn'}."\"";
-
- }elsif ($search->{'biblionumber'} ne ''){
- $query = " address@hidden 1=1007
".$search->{'biblionumber'};
-
- }elsif ($search->{'authnumber'} ne ''){
- my $n=0;
- my @ids=split / /,$search->{'authnumber'} ;
- foreach my $id (@ids){
- $query .= " address@hidden GILS 1=2057 ".$id;
- $n++;
- }
- if ($n>1){
- $query= "address@hidden ".$query;
- }
-
- }
- #add branch condition
- if ($search->{'branch'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1033
\"".$search->{'branch'}."\"";
-
- }
- # 2) do a search by keyword
- }elsif ($type eq 'keyword') {
- $search->{'keyword'}=~ s/(\\|\|)//g;;
-
- #parse the keywords
- my $keyword;
-
- if ($search->{'ttype'} eq 'exact') {
- $attr="address@hidden 4=1 address@hidden 5=1
address@hidden 2=102 ";
- } else {
- $attr=" address@hidden 4=6 address@hidden 5=103
address@hidden 2=102 ";
- }
-
-
- #Builds the query
- $query = " address@hidden 1=1016
".$attr."\"".$search->{'keyword'}."\"";
-
-
- #search by itemtypes
- if ($search->{'class'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1031
\"".$search->{'class'}."\"";
- push @params, $search->{'class'};
- }
- #search by callnumber
- if ($search->{'callno'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=20 address@hidden 4=1
address@hidden 5=1 \"".$search->{'callno'}."\"";
-
- }
- #search by branch
- if ($search->{'branch'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1033
\"".$search->{'branch'}."\"";
-
- }
- if ($search->{'stack'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1019
\"".$search->{'stack'}."\"";
- push @params, $search->{'stack'};
- }
- if ($search->{'date_from'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=30 address@hidden 2=4
address@hidden 4=4 ".$search->{'date_from'};
- push @params, $search->{'date_from'};
- }
- if ($search->{'date_to'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=30 address@hidden 2=2
address@hidden 4=4 ".$search->{'date_to'};
- push @params, $search->{'date_to'};
-
- }
-
-# 3) search the items acquired recently (in the last $search->{'range'} days)
- } elsif ($type eq 'recently_items') {
- my $keys;
- if ($search->{'range'}) {
- $keys = $search->{'range'}*(-1);
- } else {
- $keys = -30;
- }
- my @datearr = localtime();
- my $dateduef = (1900+$datearr[5])."-".sprintf ("%0.2d",
($datearr[4]+1))."-".$datearr[3];
-
-
- my ($year, $month, $day) = split /-/, $dateduef;
- ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month,
$day, ($keys - 1));
- $dateduef = "$year-$month-$day";
- $query .= " address@hidden 1=32 address@hidden 2=4
address@hidden 4=5 ".$dateduef;
- #search by class
- push @params, $keys;
- if ($search->{'class'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1031
\"".$search->{'class'}."\"";
-
- }
-
-
-
-
- # 4) do a loose search
- } else {
-
- my ($condition1, $condition2, $condition3) = ('','','');
- my $count_params = 0;
-
- if ($search->{'ttype1'} eq 'exact') {
- $attr="address@hidden 4=1 ";
- if ($search->{'atype1'} eq 'start'){
- $attr.=" address@hidden 3=1 address@hidden 6=3
address@hidden 5=1 address@hidden 2=102 ";
- }else{
- $attr.=" address@hidden 5=1 address@hidden 3=3
address@hidden 6=1 address@hidden 2=102 ";
- }
- } else {
- $attr=" address@hidden 4=6 address@hidden 5=103 ";
- }
-
- #search_field 1
- $search->{'field_value1'}=~
s/(\.|\?|\;|\=|\/|\\|\||\:|\!|,|\-|\"|\(|\)|\[|\]|\{|\}|\/)//g;
- if ($search->{'field_name1'} eq 'all') {
- $condition1.= " address@hidden 1=1016 ".$attr."
\"".$search->{'field_value1'}."\" ";
-
- } elsif ($search->{'field_name1'} eq 'author') {
- $condition1.=" address@hidden 1=1003 ".$attr."
\"".$search->{'field_value1'}."\" ";
-
- } elsif ($search->{'field_name1'} eq 'title') {
- $condition1.= " address@hidden 1=4 ".$attr."
\"".$search->{'field_value1'}."\" ";
-
- } elsif ($search->{'field_name1'} eq 'subject') {
- $condition1.=" address@hidden 1=21 ".$attr."
\"".$search->{'field_value1'}."\" ";
- } elsif ($search->{'field_name1'} eq 'series') {
- $condition1.="
address@hidden 1=5 ".$attr." \"".$search->{'field_value1'}."\" ";
-
- } elsif ($search->{'field_name1'} eq 'publisher') {
- $condition1.= " address@hidden 1=1018 ".$attr."
\"".$search->{'field_value1'}."\" ";
- } elsif ($search->{'field_name1'} eq 'callno') {
- $condition1.= " address@hidden 1=20
address@hidden 3=2 ".$attr." \"".$search->{'field_value1'}."\" ";
- }
- $query = $condition1;
- #search_field 2
- if ($search->{'field_value2'}) {
- $search->{'field_value2'}=~
s/(\.|\?|\;|\=|\/|\\|\||\:|\!|,|\-|\"|\(|\)|\[|\]|\{|\}|\/)//g;
- if ($search->{'ttype2'} eq 'exact') {
-
- $attr2="address@hidden 4=1 ";
- if ($search->{'atype1'} eq 'start'){
- $attr.=" address@hidden 3=1 address@hidden 6=3
address@hidden 5=1 address@hidden 2=102 ";
- }else{
- $attr.=" address@hidden 5=1 address@hidden 3=3
address@hidden 6=1 address@hidden 2=102 ";
- }
- } else {
- $attr2=" address@hidden 4=6 address@hidden
5=103 ";
- }
-
- if ($search->{'field_name2'} eq 'all') {
- if ($search->{'op1'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=1016 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- } elsif ($search->{'op1'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=1016 ".$attr2." \"".$search->{'field_value2'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=1016 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- }
- } elsif ($search->{'field_name2'} eq 'author') {
- if ($search->{'op1'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=1003 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- } elsif ($search->{'op1'} eq 'or'){
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=1003 ".$attr2." \"".$search->{'field_value2'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=1003 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- }
-
- } elsif ($search->{'field_name2'} eq 'title') {
- if ($search->{'op1'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=4 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- } elsif ($search->{'op1'} eq 'or'){
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=4 ".$attr2." \"".$search->{'field_value2'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=4 ".$attr2." \"".$search->{'field_value2'}."\" ";
- }
-
- } elsif ($search->{'field_name2'} eq 'subject')
{
- if ($search->{'op1'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=21 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- } elsif ($search->{'op1'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=21 ".$attr2." \"".$search->{'field_value2'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=21 ".$attr2." \"".$search->{'field_value2'}."\" ";
- }
- } elsif ($search->{'field_name2'} eq 'series') {
- if ($search->{'op1'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=5 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- } elsif ($search->{'op1'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=5 ".$attr2." \"".$search->{'field_value2'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=5 ".$attr2." \"".$search->{'field_value2'}."\" ";
- }
- } elsif ($search->{'field_name2'} eq 'callno') {
- if ($search->{'op1'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=20 address@hidden 3=2 ".$attr2." \"".$search->{'field_value2'}."\" ";
-
- } elsif ($search->{'op1'} eq 'or'){
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=20 address@hidden 3=2 ".$attr2." \"".$search->{'field_value2'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition2.= " address@hidden
1=20 address@hidden 3=2 ".$attr2." \"".$search->{'field_value2'}."\" ";
- }
- } elsif ($search->{'field_name2'} eq
'publisher') {
- $query = " address@hidden ".$query;
- $condition2.= " address@hidden 1=1018
".$attr2." \"".$search->{'field_value2'}."\" ";
- } elsif ($search->{'field_name2'} eq
'publicationyear') {
- $query = " address@hidden ".$query;
- $condition2.= " address@hidden 1=30
".$search->{'field_value2'};
- }
- $query .=$condition2;
-
-
- }
-
- #search_field 3
- if ($search->{'field_value3'}) {
- $search->{'field_value3'}=~
s/(\.|\?|\;|\=|\/|\\|\||\:|\!|,|\-|\"|\(|\)|\[|\]|\{|\}|\/)//g;
- if ($search->{'ttype3'} eq 'exact') {
- $attr3="address@hidden 4=1 ";
- if ($search->{'atype1'} eq 'start'){
- $attr.=" address@hidden 3=1 address@hidden 6=3
address@hidden 5=1 address@hidden 2=102 ";
- }else{
- $attr.=" address@hidden 5=1 address@hidden 3=3
address@hidden 6=1 address@hidden 2=102 ";
- }
- } else {
- $attr3=" address@hidden 4=6 address@hidden 5=103 ";
- }
-
- if ($search->{'field_name3'} eq 'all') {
- if ($search->{'op2'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=1016 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } elsif ($search->{'op2'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=1016 ".$attr3." \"".$search->{'field_value3'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=1016 ".$attr3." \"".$search->{'field_value3'}."\" ";
- }
- } elsif ($search->{'field_name3'} eq 'author') {
- if ($search->{'op2'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=1003 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } elsif ($search->{'op2'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=1003 ".$attr3." \"".$search->{'field_value3'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=1003 ".$attr3." \"".$search->{'field_value3'}."\" ";
- }
-
- } elsif ($search->{'field_name3'} eq 'title') {
- if ($search->{'op2'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=4 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } elsif ($search->{'op2'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=4 ".$attr3." \"".$search->{'field_value3'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=4 ".$attr3." \"".$search->{'field_value3'}."\" ";
- }
-
- } elsif ($search->{'field_name3'} eq 'subject')
{
- if ($search->{'op2'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=21 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } elsif ($search->{'op2'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=21 ".$attr3." \"".$search->{'field_value3'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=21 ".$attr3." \"".$search->{'field_value3'}."\" ";
- }
- } elsif ($search->{'field_name3'} eq 'series') {
- if ($search->{'op2'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=5 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } elsif ($search->{'op2'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=5 ".$attr3." \"".$search->{'field_value3'}."\" ";
- } else {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=5 ".$attr3." \"".$search->{'field_value3'}."\" ";
- }
- } elsif ($search->{'field_name3'} eq 'callno') {
- if ($search->{'op2'} eq 'and') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=20 address@hidden 3=2 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } elsif ($search->{'op2'} eq 'or') {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=20 address@hidden 3=2 ".$attr3." \"".$search->{'field_value3'}."\" ";
-
- } else {
- $query = " address@hidden
".$query;
- $condition3.= " address@hidden
1=20 address@hidden 3=2 ".$attr3." \"".$search->{'field_value3'}."\" ";
- }
-
-
- } elsif ($search->{'field_name3'} eq
'publisher') {
- $query = " address@hidden ".$query;
- $condition3.= " address@hidden 1=1018
".$attr3." \"".$search->{'field_value3'}."\" ";
- } elsif ($search->{'field_name2'} eq
'publicationyear') {
- $query = " address@hidden ".$query;
- $condition3.= " address@hidden 1=30
".$search->{'field_value3'};
- }
- $query .=$condition3;
-
-
- }
-
-
-
- #search by class
- if ($search->{'class'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1031
\"".$search->{'class'}."\"";
- push @params, $search->{'class'};
- }
- #search by branch
- if ($search->{'branch'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1033
\"".$search->{'branch'}."\"";
-#
- }
- if ($search->{'stack'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=1019
\"".$search->{'stack'}."\"";
-
- }
- if ($search->{'date_from'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=30 address@hidden 2=4
address@hidden 4=4 ".$search->{'date_from'};
- }
- if ($search->{'date_to'} ne '') {
- $query= "address@hidden ".$query;
- $query .= " address@hidden 1=30 address@hidden 2=2
address@hidden 4=4 ".$search->{'date_to'};
-
- }
-
- }
-
- if ($cql) {
- warn "STILL CQL";
- $count_query = $cql_query;
- $query=1;
- } else {
- $count_query = $query;
- }
- warn "QUERY_AFTER".$count_query;
- if ($search->{'order'}) {
- $query.=" ".$search->{'order'};
- $query=" address@hidden address@hidden ".$query;
- }
-#warn $query;
- #execute the query and returns just the results between $num and $num +
$offset
- my $limit = $num + $offset;
- my $startfrom = $offset;
-return unless $query; ##Somebody hit the search button with no query. Prevent
a system crash
-my $oConnection=C4::Context->Zconn("biblioserver");
-if ($oConnection eq "error"){
- return("error",undef);
- }
-#$oConnection->option(preferredRecordSyntax => "XML");
-my $oResult;
-my $newq;
-if ($cql) {
- warn "CQLISH:".$cql_query;
- if ($rpn) {
- $newq= new ZOOM::Query::PQF($cql_query);
- } else {
- $newq = new ZOOM::Query::CQL($cql_query,$oConnection);
- }
-} else {
- $newq= new ZOOM::Query::PQF($query);
-}
-#my $order=$search->{'order'};
-#if ($order){
-#$newq->sortby("$order");
-#}
-eval {
-$oResult= $oConnection->search($newq);
-};
-if($@){
- return("error",undef);
- }
-
-
-
- $numresults=$oResult->size() if ($oResult);
-
- my $i = 0;
-
- #proccess just the results to show
- if ($numresults>0) {
-#Build brancnames hash
-#find branchname
-#get branch information.....
-my %branches;
- my $bsth=$dbh->prepare("SELECT branchcode,branchname FROM
branches");
- $bsth->execute();
- while (my $bdata=$bsth->fetchrow_hashref){
- $branches{$bdata->{'branchcode'}}=
$bdata->{'branchname'};
-
- }
-
-#Building shelving hash
-my %shelves;
-#find shelvingname
-my $stackstatus = $dbh->prepare('select authorised_value from
marc_subfield_structure where kohafield="items.stack"');
- $stackstatus->execute;
-
- my ($authorised_valuecode) = $stackstatus->fetchrow;
- if ($authorised_valuecode) {
- $stackstatus = $dbh->prepare("select
lib,authorised_value from authorised_values where category=? ");
- $stackstatus->execute($authorised_valuecode);
-
- while (my $lib = $stackstatus->fetchrow_hashref){
- $shelves{$lib->{'authorised_value'}} = $lib->{'lib'};
- }
- }
-
-#search item field code
- my $sth =
- $dbh->prepare(
-"select tagfield from marc_subfield_structure where kohafield like
'items.itemnumber'"
- );
- $sth->execute;
- my ($itemtag) = $sth->fetchrow;
-## 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 ($tagfield,$tagsubfield) =
&MARCfind_marc_from_kohafield($dbh,"items.".$column,"");
-$subfieldstosearch{$column}=$tagsubfield;
-}
-
- for ($i=$startfrom; $i<(($startfrom+$num<=$numresults) ?
($startfrom+$num):$numresults) ; $i++){
-
- my $rec=$oResult->record($i);
-
- $marcdata = $rec->raw();
- my $marcrecord;
- $marcrecord = MARC::File::USMARC::decode($marcdata);
-# $marcrecord=MARC::Record->new_from_xml( $marcdata,'UTF-8' );
-# $marcrecord->encoding( 'UTF-8' );
- my $oldbiblio = MARCmarc2koha($dbh,$marcrecord,'');
-
- &add_html_bold_fields($type,$oldbiblio,$search);
- if ($i % 2) {
- $toggle="#ffffcc";
- } else {
- $toggle="white";
- }
- $oldbiblio->{'toggle'}=$toggle;
-
-
-
- my @fields = $marcrecord->field($itemtag);
-my @items;
- my $item;
-my %counts;
-$counts{'total'}=0;
-
-#
-##Loop for each item field
- foreach my $field (@fields) {
- foreach my $code ( keys %subfieldstosearch ) {
-
-$item->{$code}=$field->subfield($subfieldstosearch{$code});
-}
-
-my $status;
-
-$item->{'branchname'}=$branches{$item->{'holdingbranch'}};
-$item->{'shelves'}=$shelves{$item->{stack}};
-$status="Lost" if ($item->{'itemlost'}>0);
-$status="Withdrawn" if ($item->{'wthdrawn'}>0);
-if ($search->{'from'} eq "intranet"){
-$search->{'avoidquerylog'}=1;
-$status="Due:".format_date($item->{'onloan'}) if ($item->{'onloan'}>0);
- $status =
$item->{'holdingbranch'}."-".$item->{'stack'}."[".$item->{'itemcallnumber'}."]"
unless defined $status;
-}else{
-$status="On Loan" if ($item->{'onloan'}>0);
- $status = $item->{'branchname'}."[".$item->{'shelves'}."]" unless defined
$status;
-}
- $counts{$status}++;
-$counts{'total'}++;
-push @items,$item;
-#$oldbiblio->{'itemcount'}++;
- }
-
- my $norequests = 1;
- my $noitems = 1;
- if (@items) {
- $noitems = 0;
- foreach my $itm (@items) {
- $norequests = 0 unless $itm->{'itemnotforloan'};
- }
- }
- $oldbiblio->{'noitems'} = $noitems;
- $oldbiblio->{'norequests'} = $norequests;
- $oldbiblio->{'even'} = $even = not $even;
- $oldbiblio->{'itemcount'} = $counts{'total'};
-
- my $totalitemcounts = 0;
- foreach my $key (keys %counts){
- if ($key ne 'total'){
- $totalitemcounts+= $counts{$key};
-
$oldbiblio->{'locationhash'}->{$key}=$counts{$key};
- }
- }
-
- my ($locationtext, $locationtextonly, $notavailabletext) =
('','','');
- foreach (sort keys %{$oldbiblio->{'locationhash'}}) {
- if ($_ eq 'notavailable') {
- $notavailabletext="Not available";
- my $c=$oldbiblio->{'locationhash'}->{$_};
- $oldbiblio->{'not-available-p'}=$c;
- } else {
- $locationtext.="$_";
- my $c=$oldbiblio->{'locationhash'}->{$_};
- if ($_ eq 'Item Lost') {
- $oldbiblio->{'lost-p'} = $c;
- } elsif ($_ eq 'Withdrawn') {
- $oldbiblio->{'withdrawn-p'} = $c;
- } elsif ($_ eq 'On Loan') {
- $oldbiblio->{'on-loan-p'} = $c;
- } else {
- $locationtextonly.= $_;
- $locationtextonly.= " ($c)<br> " if
$totalitemcounts > 1;
- }
- if ($totalitemcounts>1) {
- $locationtext.=" ($c)<br> ";
- }
- }
- }
- if ($notavailabletext) {
- $locationtext.= $notavailabletext;
- } else {
- $locationtext=~s/, $//;
- }
- $oldbiblio->{'location'} = $locationtext;
- $oldbiblio->{'location-only'} = $locationtextonly;
- $oldbiblio->{'use-location-flags-p'} = 1;
-
- push (@results, $oldbiblio);
-
- }
-# $i++;
- }
-#$oConnection->destroy();
- my $count = $numresults;
-
- unless ($search->{'avoidquerylog'}) {
- add_query_line($type, $search, $count);}
- return($count,@results);
-}
-
-
-sub FindDuplicate {
- my ($record)address@hidden;
-my $dbh=C4::Context->dbh;
- my $result = MARCmarc2koha($dbh,$record,'');
- my $sth;
- my $query;
- my $search;
- my $type;
- my ($biblionumber,$bibid,$title);
- # search duplicate on ISBN, easy and fast..
-$search->{'avoidquerylog'}=1;
- if ($result->{isbn}) {
- $type="precise";
-###Temporary fix for ISBN
-my $isbn=$result->{isbn};
-$isbn=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\!|\'|,|\-|\"|\(|\)|\[|\]|\{|\}|\/)//g;
- $search->{'isbn'}=$isbn;
- }else{
-$result->{title}=~s /\\//g;
-$result->{title}=~s /\"//g;
- $type="loose";
- $search->{'field_name1'}="title";
- $search->{'field_value1'}=$result->{title};
- $search->{'ttype1'}="exact";
- $search->{'atype1'}="start";
- }
- my ($total,@result)=CatSearch4($type,$search,1,0);
- return $result[0]->{'biblionumber'},
$result[0]->{'biblionumber'},$result[0]->{'title'} if ($total);
-
-}
-=item KeywordSearch
-
- $search = { "keyword" => "One or more keywords",
- "class" => "VID|CD", # Limit search to fiction and CDs
- "dewey" => "813",
- };
- ($count, @results) = &KeywordSearch($env, $type, $search, $num, $offset);
-
-C<&KeywordSearch> searches the catalog by keyword: given a string
-(C<$search-E<gt>{"keyword"}> consisting of a space-separated list of
-keywords, it looks for books that contain any of those keywords in any
-of a number of places.
-
-C<&KeywordSearch> looks for keywords in the book title (and subtitle),
-series name, notes (both C<biblio.notes> and C<biblioitems.notes>),
-and subjects.
-
-C<$search-E<gt>{"class"}> can be set to a C<|> (pipe)-separated list of
-item class codes (e.g., "F" for fiction, "JNF" for junior nonfiction,
-etc.). In this case, the search will be restricted to just those
-classes.
-
-If C<$search-E<gt>{"class"}> is not specified, you may specify
-C<$search-E<gt>{"dewey"}>. This will restrict the search to that
-particular Dewey Decimal Classification category. Setting
-C<$search-E<gt>{"dewey"}> to "513" will return books about arithmetic,
-whereas setting it to "5" will return all books with Dewey code 5I<xx>
-(Science and Mathematics).
-
-C<$env> and C<$type> are ignored.
-
-C<$offset> and C<$num> specify the subset of results to return.
-C<$num> specifies the number of results to return, and C<$offset> is
-the number of the first result. Thus, setting C<$offset> to 100 and
-C<$num> to 5 will return results 100 through 104 inclusive.
-
-=cut
-#'
-sub KeywordSearch {
- my ($env,$type,$search,$num,$offset)address@hidden;
- my $dbh = C4::Context->dbh;
- $search->{'keyword'}=~ s/ +$//;
- my @key=split(' ',$search->{'keyword'});
- # FIXME - Naive users might enter comma-separated
- # words, e.g., "training, animal". Ought to cope with
- # this.
- my address@hidden;
- my $i=1;
- my %biblionumbers; # Set of biblionumbers returned by the
- # various searches.
-
- # FIXME - Ought to filter the stopwords out of the list of keywords.
- # @key = map { !defined($stopwords{$_}) } @key;
-
- # FIXME - The way this code is currently set up, it looks for all of
- # the keywords first in (title, notes, seriestitle), then in the
- # subtitle, then in the subject. Thus, if you look for keywords
- # "science fiction", this search won't find a book with
- # title = "How to write fiction"
- # subtitle = "A science-based approach"
- # Is this the desired effect? If not, then the first SQL query
- # should look in the biblio, subtitle, and subject tables all at
- # once. The way the first query is built can accomodate this easily.
-
- # Look for keywords in table 'biblio'.
-
- # Build an SQL query that finds each of the keywords in any of the
- # title, biblio.notes, or seriestitle. To do this, we'll build up an
- # array of clauses, one for each keyword.
- my $query; # The SQL query
- my @clauses = (); # The search clauses
- my @bind = (); # The term bindings
-
- $query = <<EOT; # Beginning of the query
- SELECT biblionumber
- FROM biblio
- WHERE
-EOT
- foreach my $keyword (@key)
- {
- my @subclauses = (); # Subclauses, one for each field we're
- # searching on
-
- # For each field we're searching on, create a subclause that'll
- # match the current keyword in the current field.
- foreach my $field (qw(title notes seriestitle author))
- {
- push @subclauses,
- "$field LIKE ? OR $field LIKE ?";
- push(@bind,"\Q$keyword\E%","% \Q$keyword\E%");
- }
- # (Yes, this could have been done as
- # @subclauses = map {...} qw(field1 field2 ...)
- # )but I think this way is more readable.
-
- # Construct the current clause by joining the subclauses.
- push @clauses, "(" . join(")\n\tOR (", @subclauses) . ")";
- }
- # Now join all of the clauses together and append to the query.
- $query .= "(" . join(")\nAND (", @clauses) . ")";
-
- # FIXME - Perhaps use $sth->bind_columns() ? Documented as the most
- # efficient way to fetch data.
- my $sth=$dbh->prepare($query);
- $sth->execute(@bind);
- while (my @res = $sth->fetchrow_array) {
- for (@res)
- {
- $biblionumbers{$_} = 1; # Add these results to the set
- }
- }
- $sth->finish;
-
- # Now look for keywords in the 'bibliosubtitle' table.
-
- # Again, we build a list of clauses from the keywords.
- @clauses = ();
- @bind = ();
- $query = "SELECT biblionumber FROM bibliosubtitle WHERE ";
- foreach my $keyword (@key)
- {
- push @clauses,
- "subtitle LIKE ? OR subtitle like ?";
- push(@bind,"\Q$keyword\E%","% \Q$keyword\E%");
- }
- $query .= "(" . join(") AND (", @clauses) . ")";
-
- $sth=$dbh->prepare($query);
- $sth->execute(@bind);
- while (my @res = $sth->fetchrow_array) {
- for (@res)
- {
- $biblionumbers{$_} = 1; # Add these results to the set
- }
- }
- $sth->finish;
-
- # Look for the keywords in the notes for individual items
- # ('biblioitems.notes')
-
- # Again, we build a list of clauses from the keywords.
- @clauses = ();
- @bind = ();
- $query = "SELECT biblionumber FROM biblioitems WHERE ";
- foreach my $keyword (@key)
- {
- push @clauses,
- "notes LIKE ? OR notes like ?";
- push(@bind,"\Q$keyword\E%","% \Q$keyword\E%");
- }
- $query .= "(" . join(") AND (", @clauses) . ")";
-
- $sth=$dbh->prepare($query);
- $sth->execute(@bind);
- while (my @res = $sth->fetchrow_array) {
- for (@res)
- {
- $biblionumbers{$_} = 1; # Add these results to the set
- }
- }
- $sth->finish;
-
- # Look for keywords in the 'bibliosubject' table.
-
- # FIXME - The other queries look for words in the desired field that
- # begin with the individual keywords the user entered. This one
- # searches for the literal string the user entered. Is this the
- # desired effect?
- # Note in particular that spaces are retained: if the user typed
- # science fiction
- # (with two spaces), this won't find the subject "science fiction"
- # (one space). Likewise, a search for "%" will return absolutely
- # everything.
- # If this isn't the desired effect, see the previous searches for
- # how to do it.
-
- $sth=$dbh->prepare("Select biblionumber from bibliosubject where subject
- like ? group by biblionumber");
- $sth->execute("%$search->{'keyword'}%");
-
- while (my @res = $sth->fetchrow_array) {
- for (@res)
- {
- $biblionumbers{$_} = 1; # Add these results to the set
- }
- }
- $sth->finish;
-
- my $i2=0;
- my $i3=0;
- my $i4=0;
-
- my @res2;
- my @res = keys %biblionumbers;
- address@hidden;
+ my @res2;
+ my @res = keys %biblionumbers;
+ address@hidden;
$i=0;
# print "count $count";
@@ -1876,310 +714,48 @@
} else {
# $search->{'class'} was not specified
- # FIXME - This is bogus: it makes a separate query for each
- # biblioitem, and returns results in apparently random order. It'd
- # be much better to combine all of the previous queries into one big
- # one (building it up a little at a time, of course), and have that
- # big query select all of the desired fields, instead of just
- # 'biblionumber'.
-
- while ($i2 < $num && $i2 < $count){
- my $query="select * from biblio,biblioitems where
- biblio.biblionumber=? and
- biblio.biblionumber=biblioitems.biblionumber ";
- my @bind=($res[$i2+$offset]);
-
- if ($search->{'dewey'} ne ''){
- $query.= "and (dewey like ?)";
- push(@bind,"$search->{'dewey'}%");
- }
-
- my $sth=$dbh->prepare($query);
-# print $query;
- $sth->execute(@bind);
- if (my $data2=$sth->fetchrow_hashref){
- my $dewey= $data2->{'dewey'};
- my $subclass=$data2->{'subclass'};
- $dewey=~s/\.*0*$//;
- ($dewey == 0) && ($dewey='');
- ($dewey) && ($dewey.=" $subclass") ;
- $sth->finish;
- $data2->{'dewey'}=$dewey;
-
- $res2[$i]=$data2;
-#
$res2[$i]="$data2->{'author'}\t$data2->{'title'}\t$data2->{'biblionumber'}\t$data2->{'copyrightdate'}\t$dewey";
- $i++;
- }
- $i2++;
-
- }
- }
-
- #$count=$i;
- return($count,@res2);
-}
-
-sub KeywordSearch2 {
- my ($env,$type,$search,$num,$offset)address@hidden;
- my $dbh = C4::Context->dbh;
- $search->{'keyword'}=~ s/ +$//;
- my @key=split(' ',$search->{'keyword'});
- my address@hidden;
- my $i=1;
- my @results;
- my $query ="Select * from biblio,bibliosubtitle,biblioitems where
- biblio.biblionumber=biblioitems.biblionumber and
- biblio.biblionumber=bibliosubtitle.biblionumber and
- (((title like ? or title like ?)";
- my @bind=("$key[0]%","% $key[0]%");
- while ($i < $count){
- $query .= " and (title like ? or title like ?)";
- push(@bind,"$key[$i]%","% $key[$i]%");
- $i++;
- }
- $query.= ") or ((subtitle like ? or subtitle like ?)";
- push(@bind,"$key[0]%","% $key[0]%");
- for ($i=1;$i<$count;$i++){
- $query.= " and (subtitle like ? or subtitle like ?)";
- push(@bind,"$key[$i]%","% $key[$i]%");
- }
- $query.= ") or ((seriestitle like ? or seriestitle like ?)";
- push(@bind,"$key[0]%","% $key[0]%");
- for ($i=1;$i<$count;$i++){
- $query.=" and (seriestitle like ? or seriestitle like ?)";
- push(@bind,"$key[$i]%","% $key[$i]%");
- }
- $query.= ") or ((biblio.notes like ? or biblio.notes like ?)";
- push(@bind,"$key[0]%","% $key[0]%");
- for ($i=1;$i<$count;$i++){
- $query.=" and (biblio.notes like ? or biblio.notes like ?)";
- push(@bind,"$key[$i]%","% $key[$i]%");
- }
- $query.= ") or ((biblioitems.notes like ? or biblioitems.notes like ?)";
- push(@bind,"$key[0]%","% $key[0]%");
- for ($i=1;$i<$count;$i++){
- $query.=" and (biblioitems.notes like ? or biblioitems.notes like ?)";
- push(@bind,"$key[$i]%","% $key[$i]%");
- }
- if ($search->{'keyword'} =~ /new zealand/i){
- $query.= "or (title like 'nz%' or title like '% nz %' or title like '% nz'
or subtitle like 'nz%'
- or subtitle like '% nz %' or subtitle like '% nz' or author like 'nz %'
- or author like '% nz %' or author like '% nz')"
- }
- if ($search->{'keyword'} eq 'nz' || $search->{'keyword'} eq 'NZ' ||
- $search->{'keyword'} =~ /nz /i || $search->{'keyword'} =~ / nz /i ||
- $search->{'keyword'} =~ / nz/i){
- $query.= "or (title like 'new zealand%' or title like '% new zealand %'
- or title like '% new zealand' or subtitle like 'new zealand%' or
- subtitle like '% new zealand %'
- or subtitle like '% new zealand' or author like 'new zealand%'
- or author like '% new zealand %' or author like '% new zealand' or
- seriestitle like 'new zealand%' or seriestitle like '% new zealand %'
- or seriestitle like '% new zealand')"
- }
- $query .= "))";
- if ($search->{'class'} ne ''){
- my @temp=split(/\|/,$search->{'class'});
- my address@hidden;
- $query.= "and ( itemtype=?";
- push(@bind,"$temp[0]");
- for (my $i=1;$i<$count;$i++){
- $query.=" or itemtype=?";
- push(@bind,"$temp[$i]");
- }
- $query.=")";
- }
- if ($search->{'dewey'} ne ''){
- $query.= "and (dewey like '$search->{'dewey'}%') ";
- }
- $query.="group by biblio.biblionumber";
- #$query.=" order by author,title";
-# print $query;
- my $sth=$dbh->prepare($query);
- $sth->execute(@bind);
- $i=0;
- while (my $data=$sth->fetchrow_hashref){
-#FIXME: rewrite to use ? before uncomment
-# my $sti=$dbh->prepare("select dewey,subclass from biblioitems where
biblionumber=$data->{'biblionumber'}
-# ");
-# $sti->execute;
-# my ($dewey, $subclass) = $sti->fetchrow;
- my $dewey=$data->{'dewey'};
- my $subclass=$data->{'subclass'};
- $dewey=~s/\.*0*$//;
- ($dewey == 0) && ($dewey='');
- ($dewey) && ($dewey.=" $subclass");
-# $sti->finish;
-
$results[$i]="$data->{'author'}\t$data->{'title'}\t$data->{'biblionumber'}\t$data->{'copyrightdate'}\t$dewey";
-# print $results[$i];
- $i++;
- }
- $sth->finish;
- $sth=$dbh->prepare("Select biblionumber from bibliosubject where subject
- like ? group by biblionumber");
- $sth->execute("%".$search->{'keyword'}."%");
- while (my $data=$sth->fetchrow_hashref){
- $query="Select * from biblio,biblioitems where
+ # FIXME - This is bogus: it makes a separate query for each
+ # biblioitem, and returns results in apparently random order. It'd
+ # be much better to combine all of the previous queries into one big
+ # one (building it up a little at a time, of course), and have that
+ # big query select all of the desired fields, instead of just
+ # 'biblionumber'.
+
+ while ($i2 < $num && $i2 < $count){
+ my $query="select * from biblio,biblioitems where
biblio.biblionumber=? and
biblio.biblionumber=biblioitems.biblionumber ";
- @bind=($data->{'biblionumber'});
- if ($search->{'class'} ne ''){
- my @temp=split(/\|/,$search->{'class'});
- my address@hidden;
- $query.= " and ( itemtype=?";
- push(@bind,$temp[0]);
- for (my $i=1;$i<$count;$i++){
- $query.=" or itemtype=?";
- push(@bind,$temp[$i]);
- }
- $query.=")";
+ my @bind=($res[$i2+$offset]);
- }
if ($search->{'dewey'} ne ''){
$query.= "and (dewey like ?)";
push(@bind,"$search->{'dewey'}%");
}
- my $sth2=$dbh->prepare($query);
- $sth2->execute(@bind);
+
+ my $sth=$dbh->prepare($query);
# print $query;
- while (my $data2=$sth2->fetchrow_hashref){
+ $sth->execute(@bind);
+ if (my $data2=$sth->fetchrow_hashref){
my $dewey= $data2->{'dewey'};
my $subclass=$data2->{'subclass'};
$dewey=~s/\.*0*$//;
($dewey == 0) && ($dewey='');
($dewey) && ($dewey.=" $subclass") ;
-# $sti->finish;
-
$results[$i]="$data2->{'author'}\t$data2->{'title'}\t$data2->{'biblionumber'}\t$data2->{'copyrightdate'}\t$dewey";
-# print $results[$i];
- $i++;
- }
- $sth2->finish;
- }
- my $i2=1;
- @results=sort @results;
- my @res;
- address@hidden;
- $i=1;
- if ($count > 0){
- $res[0]=$results[0];
- }
- while ($i2 < $count){
- if ($results[$i2] ne $res[$i-1]){
- $res[$i]=$results[$i2];
- $i++;
- }
- $i2++;
- }
- $i2=0;
- my @res2;
- address@hidden;
- while ($i2 < $num && $i2 < $count){
- $res2[$i2]=$res[$i2+$offset];
-# print $res2[$i2];
- $i2++;
- }
$sth->finish;
-# $i--;
-# $i++;
- return($i,@res2);
-}
-
-
-sub add_query_line {
-
- my ($type,$search,$results)address@hidden;
- my $dbh = C4::Context->dbh;
- my $searchdesc = '';
- my $from;
- my $borrowernumber = $search->{'borrowernumber'};
- my $remote_IP = $search->{'remote_IP'};
- my $remote_URL= $search->{'remote_URL'};
- my $searchmode = '';
- my $searchlinkdesc = '';
-
- if ($search->{'from'}) {
- $from = $search->{'from'};
- } else {
- $from = 'opac'
- }
-
- if ($type eq 'keyword') {
- $searchdesc = $search->{'keyword'};
- if ($search->{'ttype'} eq 'exact') {
- $searchmode = 'phrase';
- } else {
- $searchmode = 'any word';
- }
- $searchlinkdesc.=
"search_type=keyword&keyword=$search->{'keyword'}&ttype=$search->{'ttype'}";
-
- } elsif ($type eq 'precise') {
- if ($search->{'itemnumber'}) {
- $searchdesc = "barcode = $search->{'itemnumber'}";
- $searchlinkdesc.=
"search_type=precise&itemnumber=$search->{'itemnumber'}";
- } else {
- $searchdesc = "isbn = $search->{'itemnumber'}";
- $searchlinkdesc.=
"search_type=precise&itemnumber=$search->{'isbn'}";
- }
-
- } elsif ($type eq 'recently_items') {
- $searchdesc = "$search->{'range'}";
- $searchlinkdesc.= "recently_items=1&search=$search->{'range'}";
- } else {
- $searchlinkdesc.= "search_type=loose";
- if ( ($search->{"field_name1"}) && ($search->{"field_value1"})
) {
- if ($search->{"ttype1"} eq 'exact') {
- $searchmode.= ' starting with ';
- } else {
- $searchmode.= ' containing ';
- }
- $searchdesc.= " | " . $search->{"field_name1"} . " = "
. $search->{"field_value1"} . " | ";
- $searchlinkdesc.=
"&ttype=$search->{'ttype1'}&field_name1=$search->{'field_name1'}&field_value1=$search->{'field_value1'}";
- }
-
- if ( ($search->{"field_name2"}) && ($search->{"field_value2"})
) {
- if ($search->{"ttype2"} eq 'exact') {
- $searchmode.= ' | starting with ';
- } else {
- $searchmode.= ' | containing ';
- }
- $searchdesc.= uc($search->{"op1"});
- $searchdesc.= " | " . $search->{"field_name2"} . " = "
. $search->{"field_value2"} . " | ";
- $searchlinkdesc.=
"&op1=$search->{'op1'}&ttype=$search->{'ttype2'}&field_name2=$search->{'field_name2'}&field_value2=$search->{'field_value2'}";
- }
+ $data2->{'dewey'}=$dewey;
- if ( ($search->{"field_name3"}) && ($search->{"field_value3"})
) {
- if ($search->{"ttype3"} eq 'exact') {
- $searchmode.= ' | starting with ';
- } else {
- $searchmode.= ' | containing ';
- }
- $searchdesc.= uc($search->{"op2"});
- $searchdesc.= " | " . $search->{"field_name3"} . " = "
. $search->{"field_value3"} . " | ";
- $searchlinkdesc.=
"&op2=$search->{'op2'}&ttype=$search->{'ttype3'}&field_name3=$search->{'field_name3'}&field_value3=$search->{'field_value3'}";
- }
+ $res2[$i]=$data2;
+#
$res2[$i]="$data2->{'author'}\t$data2->{'title'}\t$data2->{'biblionumber'}\t$data2->{'copyrightdate'}\t$dewey";
+ $i++;
}
+ $i2++;
- if ($search->{'branch'}) {
- $searchdesc.= " AND branch = $search->{'branch'}";
- $searchlinkdesc.= "&branch=$search->{'branch'}";
}
- if ($search->{'class'}) {
- $searchdesc.= " AND itemtype = $search->{'class'}";
- $searchlinkdesc.= "&class=$search->{'class'}";
}
-# my $sth = $dbh->prepare("INSERT INTO querys_log (searchtype,
searchdesc, searchmode, borrowernumber, number_of_results, date, execute_from,
remote_IP, linkdesc) VALUES (?,?,?,?,?,NOW(),?,?,?)");
-# $sth->execute($type, $searchdesc, $searchmode, $borrowernumber,
$results, $from, $remote_IP, $searchlinkdesc);
-# $sth->finish;
-my $sth = $dbh->prepare("INSERT INTO
phrase_log(phr_phrase,phr_resultcount,phr_ip,user,actual) VALUES(?,?,?,?,?)");
-
-
-$sth->execute($searchdesc,$results,$remote_IP,$borrowernumber,$remote_URL);
-$sth->finish;
-
+ #$count=$i;
+ return($count,@res2);
}
-
-
=item CatSearch
($count, @results) = &CatSearch($env, $type, $search, $num, $offset);
@@ -2619,44 +1195,6 @@
return($count,@results);
}
-sub updatesearchstats{
- my ($dbh,$query)address@hidden;
-
-}
-
-=item subsearch
-
- @results = &subsearch($env, $subject);
-
-Searches for books that have a subject that exactly matches
-C<$subject>.
-
-C<&subsearch> returns an array of results. Each element of this array
-is a string, containing the book's title, author, and biblionumber,
-separated by tabs.
-
-C<$env> is ignored.
-
-=cut
-#'
-sub subsearch {
- my ($env,$subject)address@hidden;
- my $dbh = C4::Context->dbh;
- my $sth=$dbh->prepare("Select * from biblio,bibliosubject where
- biblio.biblionumber=bibliosubject.biblionumber and
- bibliosubject.subject=? group by biblio.biblionumber
- order by biblio.title");
- $sth->execute($subject);
- my $i=0;
- my @results;
- while (my $data=$sth->fetchrow_hashref){
- push @results, $data;
- $i++;
- }
- $sth->finish;
- return(@results);
-}
-
=item ItemInfo
@results = &ItemInfo($env, $biblionumber, $type);
@@ -2718,7 +1256,7 @@
$sth->execute($biblionumber);
my $i=0;
my @results;
-my ($date_due, $count_reserves);
+ my ($date_due, $count_reserves);
while (my $data=$sth->fetchrow_hashref){
my $datedue = '';
my $isth=$dbh->prepare("Select issues.*,borrowers.cardnumber
from issues,borrowers where itemnumber = ? and returndate is null and
issues.borrowernumber=borrowers.borrowernumber");
@@ -2726,7 +1264,7 @@
if (my $idata=$isth->fetchrow_hashref){
$data->{borrowernumber} = $idata->{borrowernumber};
$data->{cardnumber} = $idata->{cardnumber};
- $datedue = format_date($idata->{'date_due'});
+ $datedue = $idata->{'date_due'};
#format_date($idata->{'date_due'});
}
if ($datedue eq ''){
# $datedue="Available";
@@ -2743,7 +1281,7 @@
if (my $bdata=$bsth->fetchrow_hashref){
$data->{'branchname'} = $bdata->{'branchname'};
}
- my $date=format_date($data->{'datelastseen'});
+ my $date=$data->{'datelastseen'};
#format_date($data->{'datelastseen'});
$data->{'datelastseen'}=$date;
$data->{'datedue'}=$datedue;
$data->{'count_reserves'} = $count_reserves;
@@ -4046,10 +2584,26 @@
my $marcsubjct;
foreach my $field ($record->field('6..')) {
+ my @subfields_loop;
#my $value = $field->subfield('a');
#$marcsubjct = {MARCSUBJCT => $value,};
- $marcsubjct = {MARCSUBJCT => $field->as_string(),};
- push @marcsubjcts, $marcsubjct;
+ my @subfields = $field->subfields();
+ #warn "subfields:".join " ", @$subfields;
+ my $counter = 0;
+ my @link_loop;
+ for my $subject_subfield (@subfields ) {
+ my $code = $subject_subfield->[0];
+ my $value = $subject_subfield->[1];
+ my $linkvalue = $value;
+ my $operator = " and " unless $counter==0;
+ push @link_loop, {link => $linkvalue, operator =>
$operator };
+ my $separator = C4::Context->preference("authoritysep")
unless $counter==0;
+ push @subfields_loop, {code => $code, value => $value,
link_loop => address@hidden, separator => $separator};
+ $counter++;
+ }
+ push @marcsubjcts, { MARCSUBJECT_SUBFIELDS_LOOP =>
address@hidden };
+ #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
+ #push @marcsubjcts, $marcsubjct;
#$subjct = $value;
}
@@ -4069,30 +2623,24 @@
$maxtag = "619";
}
-my $record=MARCgetbiblio($dbh,$bibid);
+ my $record=MARCgetbiblio($dbh,$bibid);
my @marcurls;
my $url = "";
my $subfil = "";
my $marcurl;
-
foreach my $field ($record->field('856')) {
-
-
my $value = $field->subfield('u');
-# my $subfil = $data->[1];
if ( $value ne $url) {
- $marcurl = {MARCURLS => $value,};
+ $marcurl = {MARCURL => $value,};
push @marcurls, $marcurl;
$url = $value;
}
}
-
-
my address@hidden;
return $marcurlsarray;
} #end getMARCurls
-
+# deprecated
sub searchZOOM {
my
($search_or_scan,$type,$query,$num,$startfrom,$then_sort_by,$expanded_facet) =
@_;
# establish database connections
@@ -4104,27 +2652,27 @@
return("error with connection",undef); #FIXME: better error handling
}
- my $zoom_query_obj;
+ my $koha_query_obj;
# prepare the query depending on the type
if ($type eq 'ccl') {
#$query =~ s/(\(|\))//g;
eval {
- $zoom_query_obj = new ZOOM::Query::CCL2RPN($query,$zconn);
+ $koha_query_obj = new ZOOM::Query::CCL2RPN($query,$zconn);
};
if ($@) {
return ("error: Sorry, there was a problem with your query:
$@",undef); #FIXME: better error handling
}
} elsif ($type eq 'cql') {
eval {
- $zoom_query_obj = new ZOOM::Query::CQL2RPN($query,$zconn);
+ $koha_query_obj = new ZOOM::Query::CQL2RPN($query,$zconn);
};
if ($@) {
return ("error: Sorry, there was a problem with your query:
$@",undef); #FIXME: better error handling
}
} else {
eval {
- $zoom_query_obj = new ZOOM::Query::PQF($query);
+ $koha_query_obj = new ZOOM::Query::PQF($query);
};
if ($@) {
return("error with search: $@",undef); #FIXME: better error
handling
@@ -4137,14 +2685,14 @@
my $numresults;
if ($search_or_scan =~ /scan/) {
eval {
- $result = $zconn->scan($zoom_query_obj);
+ $result = $zconn->scan($koha_query_obj);
};
if ($@) {
return ("error with scan: $@",undef);
}
} else {
eval {
- $result = $zconn->search($zoom_query_obj);
+ $result = $zconn->search($koha_query_obj);
};
if ($@) {
return("error with search: $@",undef); #FIXME: better error
handling
@@ -4159,7 +2707,7 @@
my $facets_counter = ();
my $facets_info = ();
my $facets = [ {
- link_value => 'su-t',
+ link_value => 'su',
label_value => 'Subject - Topic',
tags => ['650', '651',],
subfield => 'a',
@@ -4286,114 +2834,404 @@
return(undef,$numresults,address@hidden,@results);
}
+
+# performs the search
sub getRecords {
- my ($zoom_query_ref,$sort_by_ref,$servers_ref,$count,$offset) = @_;
- my @zoom_query = @$zoom_query_ref;
+ my
($koha_query,$federated_query,$sort_by_ref,$servers_ref,$results_per_page,$offset,$expanded_facet,$branches,$query_type,$scan)
= @_;
my @servers = @$servers_ref;
my @sort_by = @$sort_by_ref;
- # build the query string
- my $zoom_query;
- foreach my $query (@zoom_query) {
- $zoom_query.="$query " if $query;
- }
-
# create the zoom connection and query object
my $zconn;
my @zconns;
my @results;
- my @results_array; # stores the final array of hashes of arrays
+ my $results_hashref =();
+
+ ### FACETED RESULTS
+ my $facets_counter = ();
+ my $facets_info = ();
+ my $facets = getFacets();
+
+ #### INITIALIZE SOME VARS USED CREATE THE FACETED RESULTS
+ my @facets_loop; # stores the ref to array of hashes for template
+
for (my $i = 0; $i < @servers; $i++) {
+ #warn "server: $servers[$i]";
$zconns[$i] = new ZOOM::Connection($servers[$i], 0,
async => 1, # asynchronous mode
- count => 1, # piggyback retrieval count
+ # count => 1, # piggyback retrieval count
preferredRecordSyntax => "usmarc");
$zconns[$i]->option( cclfile=> "/koha/etc/ccl.properties");
# perform the search, create the results objects
- $results[$i] = $zconns[$i]->search(new
ZOOM::Query::CCL2RPN($zoom_query,$zconns[$i]));
-
+ # if this is a local search, use the $koha-query, if it's a
federated one, use the federated-query
+ my $query_to_use;
+ if ($servers[$i] =~ /localhost/) {
+ $query_to_use = $koha_query;
+ }
+ else {
+ $query_to_use = $federated_query;
+ }
+ #warn "query: $query_to_use";
+ # check if we've got a query_type defined
+ eval {
+ if ($query_type) {
+ if ($query_type =~/^ccl/) {
+ #$zconns[$i]->option( cclqual=>
C4::Context->preference("CCLProperties"));
+ $query_to_use =~ s/\:/\=/g; # change : to =
last minute (FIXME)
+ $results[$i] = $zconns[$i]->search(new
ZOOM::Query::CCL2RPN($query_to_use,$zconns[$i]));
+ }
+ elsif ($query_type =~/^cql/) {
+ $results[$i] = $zconns[$i]->search(new
ZOOM::Query::CQL($query_to_use,$zconns[$i]));
+ }
+ elsif ($query_type =~/^pqf/) {
+ $results[$i] = $zconns[$i]->search(new
ZOOM::Query::PQF($query_to_use,$zconns[$i]));
+ }
+ }
+ else {
+ if ($scan) {
+ warn "preparing to scan";
+ $results[$i] = $zconns[$i]->scan(new
ZOOM::Query::CCL2RPN($query_to_use,$zconns[$i]));
+ } else {
+ $results[$i] = $zconns[$i]->search(new
ZOOM::Query::CCL2RPN($query_to_use,$zconns[$i]));
+ }
+ }
+ };
+ if ($@) {
+ warn "prob ".$@;
+ }
+ #warn "after query";
# concatenate the sort_by limits and pass them to the results object
my $sort_by;
foreach my $sort (@sort_by) {
+ warn "sorting:$sort";
$sort_by.=$sort." "; # used to be $sort,
}
$results[$i]->sort("yaz", $sort_by) if $sort_by;
}
while ((my $i = ZOOM::event(address@hidden)) != 0) {
my $ev = $zconns[$i-1]->last_event();
- #print("<td><tr>connection ", $i-1, ": ", ZOOM::event_str($ev),
"</tr></td>\n");
+ #warn ("connection ", $i-1, ": ", ZOOM::event_str($ev), ":
$servers[$i-1]\n");
if ($ev == ZOOM::Event::ZEND) {
+ #warn "ended connection: $servers[$i-1]\n";
my $size = $results[$i-1]->size();
- if ($size) {
+ #warn "$size hits found\n";
+ if ($size > 0) {
my $results_hash;
- $results_hash->{'server'} = $servers[$i-1];
+ #$results_hash->{'server'} = $servers[$i-1];
+
+ # loop through the results
$results_hash->{'hits'} = $size;
- for ( my $j=$offset; $j<(($offset+$count<=$size) ?
($offset+$count):$size) ; $j++){
+ my $times;
+ if ($offset+$results_per_page<=$size) {
+ $times= $offset+$results_per_page;
+ } else {
+ $times = $size;
+ }
+ for ( my $j=$offset; $j<$times;$j++){
#(($offset+$count<=$size) ? ($offset+$count):$size) ; $j++){
my $records_hash;
- my $record = $results[$i-1]->record($j)->raw();
- warn $record;
- my ($error,$final_record) =
changeEncoding($record,'MARC','MARC21','UTF-8');
- $records_hash->{'record'} = $final_record;
- $results_hash->{'RECORDS'}[$j] = $records_hash;
- my $dbh = C4::Context->dbh;
- use MARC::Record;
- my $record_obj =
MARC::Record->new_from_usmarc($final_record);
- my $oldbiblio = MARCmarc2koha($dbh,$record_obj,'');
- $results_hash->{'BIBLIOS'}[$j] = $oldbiblio;
-
+ my $record;
+ my $facet_record;
+ ## This is just an index scan
+ if ($scan) {
+ my ($term,$occ) = $results[$i-1]->term($j);
+ # here we create a minimal MARC record and hand
it off to the
+ # template just like a normal result ...
perhaps not ideal, but
+ # it works for now FIXME: distinguish between
MARC21 and UNIMARC
+ # use MARC::Record;
+ my $tmprecord = MARC::Record->new();
+ $tmprecord->encoding('UTF-8');
+ my $tmptitle = MARC::Field->new( '245',' ',' ',
+ a => $term,
+ b => $occ);
+ $tmprecord->append_fields($tmptitle);
+ $results_hash->{'RECORDS'}[$j]
= $tmprecord->as_usmarc();
+ #warn
"SCAN:".$tmprecord->as_usmarc();
+ }
+ else {
+ $record =
$results[$i-1]->record($j)->raw();
+ #warn "RECORD $j:".$record;
+ $results_hash->{'RECORDS'}[$j] = $record; # making a
reference to a hash
+ # Fill the facets while we're
looping
+ $facet_record =
MARC::Record->new_from_usmarc($record);
+ #warn
$servers[$i-1].$facet_record->title();
+ for (my
$k=0;$k<address@hidden;$k++) {
+ if ($facets->[$k]) {
+ my @fields;
+ for my $tag
(@{$facets->[$k]->{'tags'}}) {
+ push @fields,
$facet_record->field($tag);
+ }
+ for my $field (@fields) {
+ my @subfields = $field->subfields();
+ for my $subfield (@subfields) {
+ my ($code,$data) = @$subfield;
+ if ($code eq
$facets->[$k]->{'subfield'}) {
+ $facets_counter->{
$facets->[$k]->{'link_value'} }->{ $data }++;
+ }
+ }
}
- push @results_array, $results_hash;
+ $facets_info->{
$facets->[$k]->{'link_value'} }->{ 'label_value' } =
$facets->[$k]->{'label_value'};
+ $facets_info->{
$facets->[$k]->{'link_value'} }->{ 'expanded' } = $facets->[$k]->{'expanded'};
+ }
+ }
+ }
+ }
+ $results_hashref->{$servers[$i-1]} = $results_hash;
}
#print "connection ", $i-1, ": $size hits";
#print $results[$i-1]->record(0)->render() if $size > 0;
+ # BUILD FACETS
+ for my $link_value ( sort { $facets_counter->{$b} <=>
$facets_counter->{$a} } keys %$facets_counter) {
+ my $expandable;
+ my $number_of_facets;
+ my @this_facets_array;
+ for my $one_facet (sort { $facets_counter->{ $link_value }->{$b} <=>
$facets_counter->{ $link_value }->{$a} } keys %{$facets_counter->{ $link_value
}} ) {
+ $number_of_facets++;
+ if (($number_of_facets < 6) || ($expanded_facet eq $link_value) ||
($facets_info->{ $link_value }->{ 'expanded'})) {
+
+ # sanitize the link value ), ( 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;
+ $facet_label_value = substr($one_facet,0,20)."..." unless
length($facet_label_value)<=20;
+ # well, if it's a branch, label by the name, not the code
+ if ($link_value =~/branch/) {
+ $facet_label_value =
$branches->{$one_facet}->{'branchname'};
+ }
+
+ # but we're down with the whole label being in the link's title
+ my $facet_title_value = $one_facet;
+
+ push @this_facets_array ,
+ ( { facet_count => $facets_counter->{ $link_value }->{
$one_facet },
+ facet_label_value => $facet_label_value,
+ facet_title_value => $facet_title_value,
+ facet_link_value => $facet_link_value,
+ type_link_value => $link_value,
+ },
+ );
}
}
- return (undef, @results_array);
-}
+ unless ($facets_info->{ $link_value }->{ 'expanded'}) {
+ $expandable=1 if (($number_of_facets > 6) && ($expanded_facet ne
$link_value));
+ }
+ push @facets_loop,
+ ( { type_link_value => $link_value,
+ type_id => $link_value."_id",
+ type_label => $facets_info->{ $link_value }->{ 'label_value' },
+ facets => address@hidden,
+ expandable => $expandable,
+ expand => $link_value,
+ }
+ );
+ }
+ }
+ }
+ return (undef, $results_hashref, address@hidden);
+}
+# build the query itself
sub buildQuery {
- my ($operators,$operands,$limits,$sort_by) = @_;
+ my ($query,$operators,$operands,$indexes,$limits,$sort_by) = @_;
my @operators = @$operators if $operators;
+ my @indexes = @$indexes if $indexes;
my @operands = @$operands if $operands;
my @limits = @$limits if $limits;
my @sort_by = @$sort_by if $sort_by;
+
+ my $human_search_desc; # a human-readable query
+ my $machine_search_desc; #a machine-readable query
+ # FIXME: the locale should be set based on the syspref
+ my $stemmer = Lingua::Stem->new(-locale => 'EN-US');
+ # FIXME: these should be stored in the db so the librarian can modify
the behavior
+ $stemmer->add_exceptions({ 'and' => 'and',
+ 'or' => 'or',
+ 'not' =>
'not',});
+
+ # STEP I: determine if this is a form-based / simple query or if it's
complex (if complex,
+ # we can't handle field weighting, stemming until a formal query parser
is written
+ # I'll work on this soon -- JF
+ #if (!$query) { # form-based
+ # check if this is a known query language query, if it is, return
immediately:
+ if ($query =~/^ccl=/) {
+ return (undef,$',$',$','ccl');
+ }
+ if ($query =~/^cql=/) {
+ return (undef,$',$',$','cql');
+ }
+ if ($query =~/^pqf=/) {
+ return (undef,$',$',$','pqf');
+ }
+ if ($query =~/(\(|\))/ ) { # sorry, too complex
+ return (undef,$query,$query,$query,'ccl');
+ }
+ # form-based queries are limited to non-nested a specific depth, so we
can easily
+ # modify the incoming query operands and indexes to do stemming and
field weighting
+ # Once we do so, we'll end up with a value in $query, just like if we
had an
+ # incoming $query from the user
+ else {
+ $query = ""; # clear it out so we can populate properly with
field-weighted stemmed query
my $previous_operand; # a flag used to keep track if there was a
previous query
# if there was, we can apply the current operator
- my @ccl;
-
- # construct the query with operators
for (my $i=0; $i<address@hidden; $i++) {
+ my $operand = $operands[$i];
+ my $index = $indexes[$i];
+ my $stemmed_operand;
+ # FIXME: these should be sysprefs
+ my $stemming = 1; my $weight_fields = 1;
+
if ($operands[$i]) {
+ # STEMMING FIXME: need to refine the field
weighting so stemmed operands don't disrupt the query ranking
+ if ($stemming) {
+ my @words = split (/ /, $operands[$i]);
+ my $stems = $stemmer->stem(@words);
+ foreach my $stem(@$stems) {
+ $stemmed_operand.="$stem";
+ $stemmed_operand.="?" unless ($stem
=~/(and$|or$|not$)/) || (length($stem<3));
+ $stemmed_operand.=" ";
+ #warn "STEM: $stemmed_operand";
+ }
+ #$operand = $stemmed_operand;
+ }
+
+ # FIELD WEIGHTING - This is largely
experimental stuff. What I'm committing works
+ # pretty well but will work much better when we
have an actual query parser
+ my $weighted_query;
+ if ($weight_fields) {
+ $weighted_query.= " rk=(";
# Specifies that we're applying rank
+ # keyword has different weight
properties
+ if (($index =~ /kw/) || (!$index)) { #
FIXME: do I need to add right-truncation in the case of stemming?
+
+ # a simple way to find out if
this query uses an index
+ if ($operand =~ /(\=|\:)/) {
+ $weighted_query .= "
$operand";
+ }
+ else {
+ $weighted_query .= "
Title-cover,ext,r1=$operand"; # index label as exact
+ $weighted_query .= " or ti,ext,r2=$operand";
# index as exact
+ #$weighted_query .= " or ti,phr,r3=$operand";
# index as phrase
+ #$weighted_query .= " or any,ext,r4=$operand";
# index as exact
+ $weighted_query .= " or kw,wrdl,r5=$operand";
# index as exact
+ $weighted_query .= " or
wrd,fuzzy,r9=$operand";
+ #$weighted_query .= "
or wrd=$stemmed_operand" if $stemming;
+ }
+ }
+ elsif ($index =~ /au/) {
+ $weighted_query .= " $index,ext,r1=$operand"; #
index label as exact
+ #$weighted_query .= " or (title-sort-az=0 or
$index,startswithnt,st-word,r3=$operand #)";
+ $weighted_query .= " or
$index,phr,r3=$operand"; # index as phrase
+ $weighted_query .= " or $index,rt,wrd,r3=$operand";
+
+ }
+ elsif ($index =~ /ti/) {
+ $weighted_query .= " Title-cover,ext,r1=$operand";
# index label as exact
+ $weighted_query .= " or
Title-series,ext,r2=$operand";
+ $weighted_query .= " or
(title-sort-az=0 or Title-cover,startswithnt,st-word,r3=$operand #)";
+ #$weighted_query .= " or
(title-sort-az=0 or Title-cover,phr,r4=$operand)";
+ #$weighted_query .= " or
Title-cover,wrd,r5=$operand";
+ #$weighted_query .= " or
ti,ext,r6=$operand";
+ #$weighted_query .= " or
ti,startswith,phr,r7=$operand";
+ #$weighted_query .= " or
ti,phr,r8=$operand";
+ #$weighted_query .= " or
ti,wrd,r9=$operand";
+
+ #$weighted_query .= " or
ti,ext,r2=$operand"; # index as exact
+ #$weighted_query .= " or ti,phr,r3=$operand";
# index as phrase
+ #$weighted_query .= " or any,ext,r4=$operand";
# index as exact
+ #$weighted_query .= " or kw,wrd,r5=$operand";
# index as exact
+ }
+ else {
+ $weighted_query .= "
$index,ext,r1=$operand"; # index label as exact
+ #$weighted_query .= " or
$index,ext,r2=$operand"; # index as exact
+ $weighted_query .= " or
$index,phr,r3=$operand"; # index as phrase
+ $weighted_query .= " or
$index,rt,wrd,r3=$operand";
+ $weighted_query .= " or
$index,wrd,r5=$operand"; # index as word right-truncated
+ $weighted_query .= " or
$index,wrd,fuzzy,r8=$operand";
+ }
+ $weighted_query.=")"; # close rank specification
+ $operand = $weighted_query;
+ }
# only add an operator if there is a previous operand
if ($previous_operand) {
- if ($operators[$i]) {
- push @ccl,( {operator => $operators[$i], operand =>
$operands[$i]} );
+ if ($operators[$i-1]) {
+ $query.=" $operators[$i-1] $operand";
+ if (!$index) {
+ $human_search_desc.="
$operators[$i-1] $operands[$i]";
+ }
+ else {
+ $human_search_desc.="
$operators[$i-1] $index: $operands[$i]";
+ }
}
-
# the default operator is and
else {
- push @ccl,( {operator => 'and', operand => $operands[$i]}
);
+ $query.=" and $operand";
+ $human_search_desc.=" and
$index: $operands[$i]";
}
}
else {
- push @ccl, ( {operand => $operands[$i]} );
- $previous_operand = 1;
+ $query.=" $operand";
+ if (!$index) {
+ $human_search_desc.="
$operands[$i]";
}
+ else {
+ $human_search_desc.=" $index:
$operands[$i]";
+ }
+ $previous_operand = 1;
}
+ } #/if $operands
+ } # /for
}
# add limits
+ my $limit_query;
+ my $limit_search_desc;
foreach my $limit (@limits) {
- push @ccl, ( {limit => $limit} ) if $limit;
+ # FIXME: not quite right yet ... will work on this soon -- JF
+ if ($limit =~ /available/) {
+ $limit_query.=" and (($query and datedue=0000-00-00) or
($query and datedue=0000-00-00 not lost=1) or ($query and datedue=0000-00-00
not lost=2))";
+ $limit_search_desc.=" and available";
+ }
+ elsif (($limit_query) && ($limit =~/mc/)) {
+ $limit_query.=" or $limit" if $limit;
+ $limit_search_desc.=" or $limit" if $limit;
+ }
+ elsif (($limit_query) || ($query)) {
+ $limit_query.=" and $limit" if $limit;
+ $limit_search_desc.=" and $limit" if $limit;
}
-
- return (undef,@ccl);
+ else {
+ $limit_query.="$limit" if $limit;
+ $limit_search_desc.="$limit" if $limit;
+ }
+ }
+ $query .= $limit_query;
+ $human_search_desc .= $limit_search_desc;
+ # now normalize the strings
+ $query =~ s/ / /g; # remove extra spaces
+ $query =~ s/^ //g; # remove any beginning spaces
+ $query =~s/:/=/g; # causes probs for server
+ $query =~s/==/=/g; # remove double == from query
+
+ my $federated_query = $human_search_desc;
+ $federated_query =~ s/ / /g;
+ $federated_query =~ s/^ //g;
+ $federated_query =~ s/:/=/g;
+
+ $human_search_desc =~ s/ / /g;
+ $human_search_desc =~s/^ //g;
+ my $koha_query = $query;
+ #warn "QUERY:".$koha_query;
+ #warn "SEARCHDESC:".$human_search_desc;
+ #warn "FEDERATED QUERY:".$federated_query;
+ return (undef,$human_search_desc,$koha_query,$federated_query);
}
+
+# IMO this subroutine is pretty messy still -- it's responsible for
+# building the HTML output for the template
sub searchResults {
- my ($searchdesc,$num,$count,@marcresults)address@hidden;
- use C4::Date;
+ my
($searchdesc,$hits,$results_per_page,$offset,@marcresults)address@hidden;
my $dbh= C4::Context->dbh;
my $toggle;
@@ -4425,25 +3263,31 @@
my ($tagfield,$tagsubfield) =
&MARCfind_marc_from_kohafield($dbh,"items.".$column,"");
$subfieldstosearch{$column}=$tagsubfield;
}
- if ($num>$count) {
- $num = $count;
+ my $times;
+ if ($offset+$results_per_page<=$hits) {
+ $times= $offset+$results_per_page;
+ } else {
+ $times = $hits;
}
- for ( my $i=0; $i<$num ; $i++){
+ for ( my $i=$offset; $i<$times; $i++){
my $marcrecord;
$marcrecord = MARC::File::USMARC::decode($marcresults[$i]);
+ #warn "RECORD".$marcresults[$i];
my $oldbiblio = MARCmarc2koha($dbh,$marcrecord,'');
# add spans to search term in results
foreach my $term (@span_terms) {
+ my $old_term = $term;
if (length($term) > 3) {
- $term =~ s/(.*=|\)|\))//g;
- $oldbiblio->{'title'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'subtitle'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'author'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'publishercode'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'place'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'pages'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'notes'} =~ s/$term/<span
class=term>$term<\/span>/gi;
- $oldbiblio->{'size'} =~ s/$term/<span
class=term>$term<\/span>/gi;
+ $term =~ s/(.*=|\)|\(|\+)//g;
+ #FIXME: is there a better way to do this?
+ $oldbiblio->{'title'} =~ s/$term/<span
class=term>$&<\/span>/gi;
+ $oldbiblio->{'subtitle'} =~ s/$term/<span
class=term>$&<\/span>/gi;
+ #$oldbiblio->{'author'} =~ s/$term/<span
class=term>$&<\/span>/gi; #FIXME: add back later
+ $oldbiblio->{'publishercode'} =~ s/$term/<span
class=term>$&<\/span>/gi;
+ $oldbiblio->{'place'} =~ s/$term/<span
class=term>$&<\/span>/gi;
+ $oldbiblio->{'pages'} =~ s/$term/<span
class=term>$&<\/span>/gi;
+ $oldbiblio->{'notes'} =~ s/$term/<span
class=term>$&<\/span>/gi;
+ $oldbiblio->{'size'} =~ s/$term/<span
class=term>$&<\/span>/gi;
}
}
@@ -4454,36 +3298,51 @@
}
$oldbiblio->{'toggle'}=$toggle;
my @fields = $marcrecord->field($itemtag);
- my @items;
- my $item;
- my %counts;
- $counts{'total'}=0;
-
-#
-##Loop for each item field
+ my @items_loop;
+ my $items;
+ my $onloan_count = 0;
+ my $wthdrawn_count = 0;
+ my $itemlost_count = 0;
+ my $norequests = 1;
foreach my $field (@fields) {
+ my $item;
foreach my $code ( keys %subfieldstosearch ) {
-
$item->{$code}=$field->subfield($subfieldstosearch{$code});
}
-
- my $status;
- $item->{'branchname'}=$branches{$item->{'homebranch'}};
- $item->{'date_due'}=$item->{onloan};
- $status="Lost" if ($item->{itemlost});
- $status="Withdrawn" if ($item->{wthdrawn});
- $status =" On loan" if ($item->{onloan});
- #$status="Due:".format_date($item->{onloan}) if ($item->{onloan}>0 );
- # $status="On Loan" if ($item->{onloan} );
- if ($item->{'location'}){
- $status = $item->{'branchname'}."[".$item->{'location'}."]" unless
defined $status;
- }else{
- $status = $item->{'branchname'} unless defined $status;
+ if ($item->{wthdrawn}) {
+ $wthdrawn_count++;
}
- $counts{$status}++;
- $counts{'total'}++;
- push @items,$item;
+ elsif ($item->{itemlost}) {
+ $itemlost_count++;
}
+ elsif (($item->{onloan}) && ($item->{onloan} !=
'0000-00-00')) {
+ $onloan_count++;
+ $norequests = 0;
+ }
+ else {
+ $norequests = 0;
+ if ($item->{'holdingbranch'}) {
+
$items->{$item->{'holdingbranch'}}->{count}++;
+ }
+ elsif ($item->{'homebranch'}) {
+
$items->{$item->{'homebranch'}}->{count}++;
+ }
+ }
+ } # notforloan, item level and biblioitem level
+ #
+ for my $key (keys %$items) {
+ #warn "key: $key";
+ my $this_item = { branchname => $branches{$key},
branchcode => $key, count => $items->{$key}->{count} };
+ push @items_loop, $this_item;
+ }
+ $oldbiblio->{norequests} = $norequests;
+ $oldbiblio->{items_loop} = address@hidden;
+ $oldbiblio->{onloancount} = $onloan_count;
+ $oldbiblio->{wthdrawncount} = $wthdrawn_count;
+ $oldbiblio->{itemlostcount} = $itemlost_count;
+
+=head
+Ugh ... this is ugly, I'll re-write it better above then delete it
my $norequests = 1;
my $noitems = 1;
if (@items) {
@@ -4535,12 +3394,13 @@
$oldbiblio->{'location'} = $locationtext;
$oldbiblio->{'location-only'} = $locationtextonly;
$oldbiblio->{'use-location-flags-p'} = 1;
+=cut
push (@newresults, $oldbiblio);
-
}
return @newresults;
}
+
END { } # module clean-up code here (global destructor)
1;
- [Koha-cvs] koha/C4 Search.pm [dev_week],
Joshua Ferraro <=