From 8b6036306e02e0f2c75d042d9d4bfe174d6d79dd Mon Sep 17 00:00:00 2001 From: Jared Camins-Esakov Date: Mon, 9 Jan 2012 18:27:15 -0500 Subject: [PATCH] Bug 7430: Move ModZebra out of C4::Biblio Content-Type: text/plain; charset="UTF-8" This proof-of-concept commit does the following: * Moves all the functionality from C4::Biblio::ModZebra into a new Koha::Search::Engine namespace, breaking it up into Zebra and NoZebra classes for the relevant sections. * Rather than calling ModZebra, callers should now use Koha::Search and call AddToIndexQueue() with the same arguments. * Creates a new Koha::Utils class with GetMarcFromKohaField and GetAuthType methods, in an attempt to begin the process of reducing circular dependencies * Adds a syspref SearchEngine to specify whether Zebra or NoZebra is to be used, based on the setting of NoZebra. This syspref is checked *only* in ModZebra replacement code. The NoZebra is still relied upon by *all other* search-related code. IMPORTANT NOTE: The syspref is added by the atomicupdate in installer/data/mysql/atomicupdate/bug_7430_add_searchengine_syspref IMPORTANT NOTE: NoZebra indexing is currently broken due to the lack of a get_auth_type_location() method that can be used by the Koha::Search::Engine::NoZebra class. IMPORTANT NOTE: This patch depends on the patches for bug 7284. --- C4/AuthoritiesMarc.pm | 32 +-- C4/Biblio.pm | 365 +------------------- C4/ImportBatch.pm | 1 + C4/Items.pm | 12 +- C4/Labels/Label.pm | 1 + C4/Search.pm | 206 +----------- C4/Serials.pm | 1 + Koha/Search.pm | 113 ++++++ Koha/Search/Engine.pm | 121 +++++++ Koha/Search/Engine/NoZebra.pm | 355 +++++++++++++++++++ Koha/Search/Engine/Zebra.pm | 257 ++++++++++++++ Koha/Utils.pm | 119 +++++++ acqui/addorderiso2709.pl | 1 + acqui/neworderempty.pl | 1 + authorities/authorities.pl | 1 + authorities/blinddetail-biblio-search.pl | 1 + authorities/detail-biblio-search.pl | 1 + catalogue/MARCdetail.pl | 1 + cataloguing/addbiblio.pl | 1 + cataloguing/additem.pl | 1 + cataloguing/value_builder/barcode.pl | 1 + cataloguing/value_builder/dateaccessioned.pl | 1 + circ/branchoverdues.pl | 1 + .../atomicupdate/bug_7430_add_searchengine_syspref | 8 + .../en/modules/admin/preferences/searching.pref | 7 + misc/batchImportMARCWithBiblionumbers.pl | 1 + misc/batchRebuildBiblioTables.pl | 1 + misc/migration_tools/22_to_30/missing090field.pl | 1 + misc/migration_tools/bulkmarcimport.pl | 1 + misc/migration_tools/merge_authority.pl | 1 + misc/migration_tools/rebuild_nozebra.pl | 10 +- misc/migration_tools/rebuild_zebra.pl | 1 + opac/opac-MARCdetail.pl | 1 + opac/opac-authoritiesdetail.pl | 1 + serials/serials-edit.pl | 1 + svc/bib | 1 + svc/new_bib | 1 + t/db_dependent/lib/KohaTest/AuthoritiesMarc.pm | 1 - t/db_dependent/lib/KohaTest/Biblio/ModBiblio.pm | 1 + .../KohaTest/ImportBatch/BatchStageCommitRevert.pm | 1 + tools/batchMod.pl | 1 + tools/export.pl | 1 + 42 files changed, 1035 insertions(+), 600 deletions(-) create mode 100644 Koha/Search.pm create mode 100644 Koha/Search/Engine.pm create mode 100644 Koha/Search/Engine/NoZebra.pm create mode 100644 Koha/Search/Engine/Zebra.pm create mode 100644 Koha/Utils.pm create mode 100644 installer/data/mysql/atomicupdate/bug_7430_add_searchengine_syspref diff --git a/C4/AuthoritiesMarc.pm b/C4/AuthoritiesMarc.pm index c341b02..58aa513 100644 --- a/C4/AuthoritiesMarc.pm +++ b/C4/AuthoritiesMarc.pm @@ -26,6 +26,8 @@ use C4::AuthoritiesMarc::MARC21; use C4::AuthoritiesMarc::UNIMARC; use C4::Charset; use C4::Log; +use Koha::Utils; +use Koha::Search; use vars qw($VERSION @ISA @EXPORT); @@ -37,7 +39,6 @@ BEGIN { @ISA = qw(Exporter); @EXPORT = qw( &GetTagsLabels - &GetAuthType &GetAuthTypeCode &GetAuthMARCFromKohaField @@ -729,7 +730,7 @@ sub AddAuthority { $sth->finish; logaction( "AUTHORITIES", "ADD", $authid, "authority" ) if C4::Context->preference("AuthoritiesLog"); } - ModZebra($authid,'specialUpdate',"authorityserver",$oldRecord,$record); + AddToIndexQueue($authid,'specialUpdate',"authorityserver",$oldRecord,$record); return ($authid); } @@ -747,7 +748,7 @@ sub DelAuthority { my $dbh=C4::Context->dbh; logaction( "AUTHORITIES", "DELETE", $authid, "authority" ) if C4::Context->preference("AuthoritiesLog"); - ModZebra($authid,"recordDelete","authorityserver",GetAuthority($authid),undef); + AddToIndexQueue($authid,"recordDelete","authorityserver",GetAuthority($authid),undef); my $sth = $dbh->prepare("DELETE FROM auth_header WHERE authid=?"); $sth->execute($authid); } @@ -839,31 +840,6 @@ sub GetAuthority { return ($record); } -=head2 GetAuthType - - $result = &GetAuthType($authtypecode) - -If the authority type specified by C<$authtypecode> exists, -returns a hashref of the type's fields. If the type -does not exist, returns undef. - -=cut - -sub GetAuthType { - my ($authtypecode) = @_; - my $dbh=C4::Context->dbh; - my $sth; - if (defined $authtypecode){ # NOTE - in MARC21 framework, '' is a valid authority - # type (FIXME but why?) - $sth=$dbh->prepare("select * from auth_types where authtypecode=?"); - $sth->execute($authtypecode); - if (my $res = $sth->fetchrow_hashref) { - return $res; - } - } - return; -} - =head2 FindDuplicateAuthority diff --git a/C4/Biblio.pm b/C4/Biblio.pm index 878312c..0241cba 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -39,6 +39,8 @@ use C4::Linker; require C4::Heading; require C4::Serials; require C4::Items; +use Koha::Search; +use Koha::Utils; use vars qw($VERSION @ISA @EXPORT); @@ -89,7 +91,6 @@ BEGIN { &GetAuthorisedValueDesc &GetMarcStructure - &GetMarcFromKohaField &GetFrameworkCode &TransformKohaToMarc &PrepHostMarcField @@ -134,7 +135,6 @@ BEGIN { &TransformHtmlToMarc &TransformHtmlToXml &PrepareItemrecordDisplay - &GetNoZebraIndexes ); } @@ -436,7 +436,7 @@ sub DelBiblio { # the previous version of the record $oldRecord = GetMarcBiblio($biblionumber); } - ModZebra( $biblionumber, "recordDelete", "biblioserver", $oldRecord, undef ); + AddToIndexQueue( $biblionumber, "recordDelete", "biblioserver", $oldRecord, undef ); # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems $sth = $dbh->prepare("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?"); @@ -540,7 +540,7 @@ sub LinkBibHeadingsToAuthorities { if (defined $current_link && C4::Context->preference('LinkerKeepStale')) { $results{'fuzzy'}->{$heading->display_form()}++; } elsif (C4::Context->preference('AutoCreateAuthorities')) { - my $authtypedata=C4::AuthoritiesMarc::GetAuthType($heading->auth_type()); + my $authtypedata=GetAuthType($heading->auth_type()); my $marcrecordauth=MARC::Record->new(); if (C4::Context->preference('marcflavour') eq 'MARC21') { $marcrecordauth->leader(' nz a22 o 4500'); @@ -1107,22 +1107,6 @@ sub GetUsedMarcStructure($) { return $sth->fetchall_arrayref( {} ); } -=head2 GetMarcFromKohaField - - ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode); - -Returns the MARC fields & subfields mapped to the koha field -for the given frameworkcode - -=cut - -sub GetMarcFromKohaField { - my ( $kohafield, $frameworkcode ) = @_; - return 0, 0 unless $kohafield and defined $frameworkcode; - my $relations = C4::Context->marcfromkohafield; - return ( $relations->{$frameworkcode}->{$kohafield}->[0], $relations->{$frameworkcode}->{$kohafield}->[1] ); -} - =head2 GetMarcBiblio my $record = GetMarcBiblio($biblionumber, [$embeditems]); @@ -2819,88 +2803,13 @@ $newRecord is the MARC::Record containing the new record. It is usefull only whe sub ModZebra { ###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs - my ( $biblionumber, $op, $server, $oldRecord, $newRecord ) = @_; - my $dbh = C4::Context->dbh; # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates # at the same time # replaced by a zebraqueue table, that is filled with ModZebra to run. # the table is emptied by misc/cronjobs/zebraqueue_start.pl script + AddToIndexQueue(@_) - if ( C4::Context->preference("NoZebra") ) { - - # lock the nozebra table : we will read index lines, update them in Perl process - # and write everything in 1 transaction. - # lock the table to avoid someone else overwriting what we are doing - $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ'); - my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed - if ( $op eq 'specialUpdate' ) { - - # OK, we have to add or update the record - # 1st delete (virtually, in indexes), if record actually exists - if ($oldRecord) { - %result = _DelBiblioNoZebra( $biblionumber, $oldRecord, $server ); - } - - # ... add the record - %result = _AddBiblioNoZebra( $biblionumber, $newRecord, $server, %result ); - } else { - - # it's a deletion, delete the record... - # warn "DELETE the record $biblionumber on $server".$record->as_formatted; - %result = _DelBiblioNoZebra( $biblionumber, $oldRecord, $server ); - } - - # ok, now update the database... - my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?"); - foreach my $key ( keys %result ) { - foreach my $index ( keys %{ $result{$key} } ) { - $sth->execute( $result{$key}->{$index}, $server, $key, $index ); - } - } - $dbh->do('UNLOCK TABLES'); - } else { - - # - # we use zebra, just fill zebraqueue table - # - my $check_sql = "SELECT COUNT(*) FROM zebraqueue - WHERE server = ? - AND biblio_auth_number = ? - AND operation = ? - AND done = 0"; - my $check_sth = $dbh->prepare_cached($check_sql); - $check_sth->execute( $server, $biblionumber, $op ); - my ($count) = $check_sth->fetchrow_array; - $check_sth->finish(); - if ( $count == 0 ) { - my $sth = $dbh->prepare("INSERT INTO zebraqueue (biblio_auth_number,server,operation) VALUES(?,?,?)"); - $sth->execute( $biblionumber, $server, $op ); - $sth->finish; - } - } -} - -=head2 GetNoZebraIndexes - - %indexes = GetNoZebraIndexes; - -return the data from NoZebraIndexes syspref. - -=cut - -sub GetNoZebraIndexes { - my $no_zebra_indexes = C4::Context->preference('NoZebraIndexes'); - my %indexes; - INDEX: foreach my $line ( split /['"],[\n\r]*/, $no_zebra_indexes ) { - $line =~ /(.*)=>(.*)/; - my $index = $1; # initial ' or " is removed afterwards - my $fields = $2; - $index =~ s/'|"|\s//g; - $fields =~ s/'|"|\s//g; - $indexes{$index} = $fields; - } - return %indexes; } =head2 EmbedItemsInMarcBiblio @@ -2935,268 +2844,6 @@ sub EmbedItemsInMarcBiblio { =head1 INTERNAL FUNCTIONS -=head2 _DelBiblioNoZebra($biblionumber,$record,$server); - -function to delete a biblio in NoZebra indexes -This function does NOT delete anything in database : it reads all the indexes entries -that have to be deleted & delete them in the hash - -The SQL part is done either : - - after the Add if we are modifying a biblio (delete + add again) - - immediatly after this sub if we are doing a true deletion. - -$server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself - -=cut - -sub _DelBiblioNoZebra { - my ( $biblionumber, $record, $server ) = @_; - - # Get the indexes - my $dbh = C4::Context->dbh; - - # Get the indexes - my %index; - my $title; - if ( $server eq 'biblioserver' ) { - %index = GetNoZebraIndexes; - - # get title of the record (to store the 10 first letters with the index) - my ( $titletag, $titlesubfield ) = GetMarcFromKohaField( 'biblio.title', '' ); # FIXME: should be GetFrameworkCode($biblionumber) ?? - $title = lc( $record->subfield( $titletag, $titlesubfield ) ); - } else { - - # for authorities, the "title" is the $a mainentry - my ( $auth_type_tag, $auth_type_sf ) = C4::AuthoritiesMarc::get_auth_type_location(); - my $authref = C4::AuthoritiesMarc::GetAuthType( $record->subfield( $auth_type_tag, $auth_type_sf ) ); - warn "ERROR : authtype undefined for " . $record->as_formatted unless $authref; - $title = $record->subfield( $authref->{auth_tag_to_report}, 'a' ); - $index{'mainmainentry'} = $authref->{'auth_tag_to_report'} . 'a'; - $index{'mainentry'} = $authref->{'auth_tag_to_report'} . '*'; - $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}"; - } - - my %result; - - # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values - $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g; - - # limit to 10 char, should be enough, and limit the DB size - $title = substr( $title, 0, 10 ); - - #parse each field - my $sth2 = $dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?'); - foreach my $field ( $record->fields() ) { - - #parse each subfield - next if $field->tag < 10; - foreach my $subfield ( $field->subfields() ) { - my $tag = $field->tag(); - my $subfieldcode = $subfield->[0]; - my $indexed = 0; - - # check each index to see if the subfield is stored somewhere - # otherwise, store it in __RAW__ index - foreach my $key ( keys %index ) { - - # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode"; - if ( $index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/ ) { - $indexed = 1; - my $line = lc $subfield->[1]; - - # remove meaningless value in the field... - $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g; - - # ... and split in words - foreach ( split / /, $line ) { - next unless $_; # skip empty values (multiple spaces) - # if the entry is already here, do nothing, the biblionumber has already be removed - unless ( defined( $result{$key}->{$_} ) && ( $result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/ ) ) { - - # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing - $sth2->execute( $server, $key, $_ ); - my $existing_biblionumbers = $sth2->fetchrow; - - # it exists - if ($existing_biblionumbers) { - - # warn " existing for $key $_: $existing_biblionumbers"; - $result{$key}->{$_} = $existing_biblionumbers; - $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//; - } - } - } - } - } - - # the subfield is not indexed, store it in __RAW__ index anyway - unless ($indexed) { - my $line = lc $subfield->[1]; - $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g; - - # ... and split in words - foreach ( split / /, $line ) { - next unless $_; # skip empty values (multiple spaces) - # if the entry is already here, do nothing, the biblionumber has already be removed - unless ( $result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/ ) { - - # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing - $sth2->execute( $server, '__RAW__', $_ ); - my $existing_biblionumbers = $sth2->fetchrow; - - # it exists - if ($existing_biblionumbers) { - $result{'__RAW__'}->{$_} = $existing_biblionumbers; - $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//; - } - } - } - } - } - } - return %result; -} - -=head2 _AddBiblioNoZebra - - _AddBiblioNoZebra($biblionumber, $record, $server, %result); - -function to add a biblio in NoZebra indexes - -=cut - -sub _AddBiblioNoZebra { - my ( $biblionumber, $record, $server, %result ) = @_; - my $dbh = C4::Context->dbh; - - # Get the indexes - my %index; - my $title; - if ( $server eq 'biblioserver' ) { - %index = GetNoZebraIndexes; - - # get title of the record (to store the 10 first letters with the index) - my ( $titletag, $titlesubfield ) = GetMarcFromKohaField( 'biblio.title', '' ); # FIXME: should be GetFrameworkCode($biblionumber) ?? - $title = lc( $record->subfield( $titletag, $titlesubfield ) ); - } else { - - # warn "server : $server"; - # for authorities, the "title" is the $a mainentry - my ( $auth_type_tag, $auth_type_sf ) = C4::AuthoritiesMarc::get_auth_type_location(); - my $authref = C4::AuthoritiesMarc::GetAuthType( $record->subfield( $auth_type_tag, $auth_type_sf ) ); - warn "ERROR : authtype undefined for " . $record->as_formatted unless $authref; - $title = $record->subfield( $authref->{auth_tag_to_report}, 'a' ); - $index{'mainmainentry'} = $authref->{auth_tag_to_report} . 'a'; - $index{'mainentry'} = $authref->{auth_tag_to_report} . '*'; - $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}"; - } - - # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values - $title =~ s/ |\.|,|;|\[|\]|\(|\)|\*|-|'|:|=|\r|\n//g; - - # limit to 10 char, should be enough, and limit the DB size - $title = substr( $title, 0, 10 ); - - #parse each field - my $sth2 = $dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?'); - foreach my $field ( $record->fields() ) { - - #parse each subfield - ###FIXME: impossible to index a 001-009 value with NoZebra - next if $field->tag < 10; - foreach my $subfield ( $field->subfields() ) { - my $tag = $field->tag(); - my $subfieldcode = $subfield->[0]; - my $indexed = 0; - - # warn "INDEXING :".$subfield->[1]; - # check each index to see if the subfield is stored somewhere - # otherwise, store it in __RAW__ index - foreach my $key ( keys %index ) { - - # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode"; - if ( $index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/ ) { - $indexed = 1; - my $line = lc $subfield->[1]; - - # remove meaningless value in the field... - $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g; - - # ... and split in words - foreach ( split / /, $line ) { - next unless $_; # skip empty values (multiple spaces) - # if the entry is already here, improve weight - - # warn "managing $_"; - if ( exists $result{$key}->{$_} && $result{$key}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/ ) { - my $weight = $1 + 1; - $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g; - $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;"; - } else { - - # get the value if it exist in the nozebra table, otherwise, create it - $sth2->execute( $server, $key, $_ ); - my $existing_biblionumbers = $sth2->fetchrow; - - # it exists - if ($existing_biblionumbers) { - $result{$key}->{"$_"} = $existing_biblionumbers; - my $weight = defined $1 ? $1 + 1 : 1; - $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g; - $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;"; - - # create a new ligne for this entry - } else { - - # warn "INSERT : $server / $key / $_"; - $dbh->do( 'INSERT INTO nozebra SET server=' . $dbh->quote($server) . ', indexname=' . $dbh->quote($key) . ',value=' . $dbh->quote($_) ); - $result{$key}->{"$_"} .= "$biblionumber,$title-1;"; - } - } - } - } - } - - # the subfield is not indexed, store it in __RAW__ index anyway - unless ($indexed) { - my $line = lc $subfield->[1]; - $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g; - - # ... and split in words - foreach ( split / /, $line ) { - next unless $_; # skip empty values (multiple spaces) - # if the entry is already here, improve weight - my $tmpstr = $result{'__RAW__'}->{"$_"} || ""; - if ( $tmpstr =~ /$biblionumber,\Q$title\E\-(\d+);/ ) { - my $weight = $1 + 1; - $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//; - $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;"; - } else { - - # get the value if it exist in the nozebra table, otherwise, create it - $sth2->execute( $server, '__RAW__', $_ ); - my $existing_biblionumbers = $sth2->fetchrow; - - # it exists - if ($existing_biblionumbers) { - $result{'__RAW__'}->{"$_"} = $existing_biblionumbers; - my $weight = ( $1 ? $1 : 0 ) + 1; - $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//; - $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;"; - - # create a new ligne for this entry - } else { - $dbh->do( 'INSERT INTO nozebra SET server=' . $dbh->quote($server) . ', indexname="__RAW__",value=' . $dbh->quote($_) ); - $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-1;"; - } - } - } - } - } - } - return %result; -} - =head2 _find_value ($indicators, $value) = _find_value($tag, $subfield, $record,$encoding); @@ -3715,7 +3362,7 @@ sub ModBiblioMarc { $sth = $dbh->prepare("UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?"); $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding), $biblionumber ); $sth->finish; - ModZebra( $biblionumber, "specialUpdate", "biblioserver", $oldRecord, $record ); + AddToIndexQueue( $biblionumber, "specialUpdate", "biblioserver", $oldRecord, $record ); return $biblionumber; } diff --git a/C4/ImportBatch.pm b/C4/ImportBatch.pm index b6db406..f4de6f9 100644 --- a/C4/ImportBatch.pm +++ b/C4/ImportBatch.pm @@ -25,6 +25,7 @@ use C4::Koha; use C4::Biblio; use C4::Items; use C4::Charset; +use Koha::Utils; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); diff --git a/C4/Items.pm b/C4/Items.pm index 8802a4c..b67ebe1 100644 --- a/C4/Items.pm +++ b/C4/Items.pm @@ -34,6 +34,8 @@ require C4::Reserves; use C4::Charset; use C4::Acquisition; use List::MoreUtils qw/any/; +use Koha::Utils; +use Koha::Search; use Data::Dumper; # used as part of logging item record changes, not just for # debugging; so please don't remove this @@ -268,7 +270,7 @@ sub AddItem { my ( $itemnumber, $error ) = _koha_new_item( $item, $item->{barcode} ); $item->{'itemnumber'} = $itemnumber; - ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef ); + AddToIndexQueue( $item->{biblionumber}, "specialUpdate", "biblioserver", undef, undef ); logaction("CATALOGUING", "ADD", $itemnumber, "item") if C4::Context->preference("CataloguingLog"); @@ -519,7 +521,7 @@ sub ModItem { # request that bib be reindexed so that searching on current # item status is possible - ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef ); + AddToIndexQueue( $biblionumber, "specialUpdate", "biblioserver", undef, undef ); logaction("CATALOGUING", "MODIFY", $itemnumber, Dumper($item)) if C4::Context->preference("CataloguingLog"); } @@ -582,7 +584,7 @@ sub DelItem { # get the MARC record my $record = GetMarcBiblio($biblionumber); - ModZebra( $biblionumber, "specialUpdate", "biblioserver", undef, undef ); + AddToIndexQueue( $biblionumber, "specialUpdate", "biblioserver", undef, undef ); # backup the record my $copy2deleted = $dbh->prepare("UPDATE deleteditems SET marc=? WHERE itemnumber=?"); @@ -2172,8 +2174,8 @@ sub MoveItemFromBiblio { $sth = $dbh->prepare("UPDATE items SET biblioitemnumber = ?, biblionumber = ? WHERE itemnumber = ? AND biblionumber = ?"); my $return = $sth->execute($tobiblioitem, $tobiblio, $itemnumber, $frombiblio); if ($return == 1) { - ModZebra( $tobiblio, "specialUpdate", "biblioserver", undef, undef ); - ModZebra( $frombiblio, "specialUpdate", "biblioserver", undef, undef ); + AddToIndexQueue( $tobiblio, "specialUpdate", "biblioserver", undef, undef ); + AddToIndexQueue( $frombiblio, "specialUpdate", "biblioserver", undef, undef ); # Checking if the item we want to move is in an order my $order = GetOrderFromItemnumber($itemnumber); if ($order) { diff --git a/C4/Labels/Label.pm b/C4/Labels/Label.pm index 930e0f6..a27d68a 100644 --- a/C4/Labels/Label.pm +++ b/C4/Labels/Label.pm @@ -11,6 +11,7 @@ use Data::Dumper; use C4::Context; use C4::Debug; use C4::Biblio; +use Koha::Utils; BEGIN { use version; our $VERSION = qv('1.0.0_1'); diff --git a/C4/Search.pm b/C4/Search.pm index ba132be..a22f47f 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -33,6 +33,8 @@ use C4::Debug; use C4::Items; use YAML; use URI::Escape; +use Koha::Search; +use Koha::Utils; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG); @@ -812,208 +814,6 @@ sub _build_weighted_query { return $weighted_query; } -=head2 getIndexes - -Return an array with available indexes. - -=cut - -sub getIndexes{ - my @indexes = ( - # biblio indexes - 'ab', - 'Abstract', - 'acqdate', - 'allrecords', - 'an', - 'Any', - 'at', - 'au', - 'aub', - 'aud', - 'audience', - 'auo', - 'aut', - 'Author', - 'Author-in-order ', - 'Author-personal-bibliography', - 'Authority-Number', - 'authtype', - 'bc', - 'Bib-level', - 'biblionumber', - 'bio', - 'biography', - 'callnum', - 'cfn', - 'Chronological-subdivision', - 'cn-bib-source', - 'cn-bib-sort', - 'cn-class', - 'cn-item', - 'cn-prefix', - 'cn-suffix', - 'cpn', - 'Code-institution', - 'Conference-name', - 'Conference-name-heading', - 'Conference-name-see', - 'Conference-name-seealso', - 'Content-type', - 'Control-number', - 'copydate', - 'Corporate-name', - 'Corporate-name-heading', - 'Corporate-name-see', - 'Corporate-name-seealso', - 'ctype', - 'date-entered-on-file', - 'Date-of-acquisition', - 'Date-of-publication', - 'Dewey-classification', - 'EAN', - 'extent', - 'fic', - 'fiction', - 'Form-subdivision', - 'format', - 'Geographic-subdivision', - 'he', - 'Heading', - 'Heading-use-main-or-added-entry', - 'Heading-use-series-added-entry ', - 'Heading-use-subject-added-entry', - 'Host-item', - 'id-other', - 'Illustration-code', - 'ISBN', - 'isbn', - 'ISSN', - 'issn', - 'itemtype', - 'kw', - 'Koha-Auth-Number', - 'l-format', - 'language', - 'lc-card', - 'LC-card-number', - 'lcn', - 'llength', - 'ln', - 'Local-classification', - 'Local-number', - 'Match-heading', - 'Match-heading-see-from', - 'Material-type', - 'mc-itemtype', - 'mc-rtype', - 'mus', - 'name', - 'Music-number', - 'Name-geographic', - 'Name-geographic-heading', - 'Name-geographic-see', - 'Name-geographic-seealso', - 'nb', - 'Note', - 'notes', - 'ns', - 'nt', - 'pb', - 'Personal-name', - 'Personal-name-heading', - 'Personal-name-see', - 'Personal-name-seealso', - 'pl', - 'Place-publication', - 'pn', - 'popularity', - 'pubdate', - 'Publisher', - 'Record-control-number', - 'rcn', - 'Record-type', - 'rtype', - 'se', - 'See', - 'See-also', - 'sn', - 'Stock-number', - 'su', - 'Subject', - 'Subject-heading-thesaurus', - 'Subject-name-personal', - 'Subject-subdivision', - 'Summary', - 'Suppress', - 'su-geo', - 'su-na', - 'su-to', - 'su-ut', - 'ut', - 'UPC', - 'Term-genre-form', - 'Term-genre-form-heading', - 'Term-genre-form-see', - 'Term-genre-form-seealso', - 'ti', - 'Title', - 'Title-cover', - 'Title-series', - 'Title-host', - 'Title-uniform', - 'Title-uniform-heading', - 'Title-uniform-see', - 'Title-uniform-seealso', - 'totalissues', - 'yr', - - # items indexes - 'acqsource', - 'barcode', - 'bc', - 'branch', - 'ccode', - 'classification-source', - 'cn-sort', - 'coded-location-qualifier', - 'copynumber', - 'damaged', - 'datelastborrowed', - 'datelastseen', - 'holdingbranch', - 'homebranch', - 'issues', - 'item', - 'itemnumber', - 'itype', - 'Local-classification', - 'location', - 'lost', - 'materials-specified', - 'mc-ccode', - 'mc-itype', - 'mc-loc', - 'notforloan', - 'onloan', - 'price', - 'renewals', - 'replacementprice', - 'replacementpricedate', - 'reserves', - 'restricted', - 'stack', - 'stocknumber', - 'inv', - 'uri', - 'withdrawn', - - # subject related - ); - - return \@indexes; -} - =head2 buildQuery ( $error, $query, @@ -1071,7 +871,7 @@ sub buildQuery { my $stopwords_removed; # flag to determine if stopwords have been removed my $cclq = 0; - my $cclindexes = getIndexes(); + my $cclindexes = GetIndexes(); if ( $query !~ /\s*ccl=/ ) { while ( !$cclq && $query =~ /(?:^|\W)([\w-]+)(,[\w-]+)*[:=]/g ) { my $dx = lc($1); diff --git a/C4/Serials.pm b/C4/Serials.pm index 1471184..43a8df5 100644 --- a/C4/Serials.pm +++ b/C4/Serials.pm @@ -32,6 +32,7 @@ use C4::Search; use C4::Letters; use C4::Log; # logaction use C4::Debug; +use Koha::Utils; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); diff --git a/Koha/Search.pm b/Koha/Search.pm new file mode 100644 index 0000000..d5c9d04 --- /dev/null +++ b/Koha/Search.pm @@ -0,0 +1,113 @@ +package Koha::Search; + +# Copyright 2011 C & P Bibliography Services +# +# 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 distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + +Koha::Search - Interface to bibliographic/authority record searching + +=head1 SYNOPSIS + + use Koha::Search; + +=head1 DESCRIPTION + +Interface to Koha::Search::Engine functionality for bibliographic and authority +record searching. + +=head1 FUNCTIONS + +=cut + +use strict; +use warnings; +require Exporter; +use C4::Context; +use Koha::Search::Engine; + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG); + + +BEGIN { + $VERSION = 3.01; + $DEBUG = ($ENV{DEBUG}) ? 1 : 0; + our $search_engine = Koha::Search::Engine->new(); +} + +=head1 NAME + +Koha::Search - Functions for searching the Koha catalog. + +=head1 SYNOPSIS + +See opac/opac-search.pl or catalogue/search.pl for example of usage + +=head1 DESCRIPTION + +This module provides searching functions for Koha's bibliographic databases + +=head1 FUNCTIONS + +=cut + + +@ISA = qw(Exporter); +@EXPORT = qw( + &AddToIndexQueue + &GetIndexes +); + +our $search_engine; + +sub AddToIndexQueue { + if (!(C4::Context->preference('SearchEngine')=~/IndexOff/i)){ # solr allows disabling indexing + return $search_engine->add_to_index_queue( @_ ); + } + return undef; +} + +=head2 GetIndexes + + %indexes = GetIndexes; + +Return a hash of indexes provided by the active search engine + +=cut + +sub GetIndexes { + return $search_engine->get_indexes( @_ ); +} + +=head2 EXPORT + +AddToIndexQueue +GetIndexes + +=head1 SEE ALSO + +Koha::Search::Engine::Zebra + +=head1 AUTHOR + +Jared Camins-Esakov, C & P Bibliography Services, Ejcamins@cpbibliography.comE + +=cut + +1; + +__END__ diff --git a/Koha/Search/Engine.pm b/Koha/Search/Engine.pm new file mode 100644 index 0000000..6e197eb --- /dev/null +++ b/Koha/Search/Engine.pm @@ -0,0 +1,121 @@ +package Koha::Search::Engine; + +# Copyright 2011 C & P Bibliography Services +# +# 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 distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +=head1 NAME + +Koha::Search::Engine - Base class for Koha search engine interfaces + +=head1 SYNOPSIS + + use Koha::Search::Engine; + +=head1 DESCRIPTION + +Base class for Koha::Search::Engine::X. Subclasses need to provide the +following methods: + +B - add the specified object to the index queue + +B - get a list of indexes provided by the search engine + +=head1 FUNCTIONS + +=cut + +use strict; +use warnings; +use C4::Context; + +BEGIN { + our $VERSION = 3.01; + + my $engine_module = "Koha::Search::Engine::" . (C4::Context->preference("SearchEngine") || 'Zebra'); + eval "require $engine_module"; +} + +sub new { + my $class = shift; + + my $self = { }; + + my $engine_module = "Koha::Search::Engine::" . (C4::Context->preference("SearchEngine") || 'Zebra'); + + $self->{'engine'} = $engine_module->new(); + bless $self, $class; + return $self; +} + +=head2 add_to_index_queue + + $search_engine->add_to_index_queue( $indexnumber, $op, $server, $oldRecord, $newRecord ); + +$indexnumber is the id number of the object we want to index + +$op is specialUpdate or delete, and is used to know what we want to do + +$server is the server that we want to update + +$oldRecord is the MARC::Record containing the previous version of the record. +This is used only by the NoZebra engine. + +$newRecord is the MARC::Record containing the new record. This is used only by +the NoZebra engine. + +=cut + +sub add_to_index_queue { + my $self = shift; + + return $self->{'engine'}->add_to_index_queue(@_); +} + +=head2 get_indexes + + %indexes = $search_engine->get_indexes; + +Return a hash of indexes provided by the active search engine + +=cut + + +sub get_indexes { + my $self = shift; + + return $self->{'engine'}->get_indexes(@_); +} + +=head2 EXPORT + +None by default. + +=head1 SEE ALSO + +Koha::Search +Koha::Search::Engine::NoZebra +Koha::Search::Engine::Zebra + +=head1 AUTHOR + +Jared Camins-Esakov, C & P Bibliography Services, Ejcamins@cpbibliography.comE + +=cut + +1; + +__END__ diff --git a/Koha/Search/Engine/NoZebra.pm b/Koha/Search/Engine/NoZebra.pm new file mode 100644 index 0000000..d4bd673 --- /dev/null +++ b/Koha/Search/Engine/NoZebra.pm @@ -0,0 +1,355 @@ +package Koha::Search::Engine::NoZebra; + +# Copyright 2011 C & P Bibliography Services +# +# 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 distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Context; +use Koha::Utils; + +use base qw(Koha::Search::Engine); + +sub new { + my $class = shift; + + my $self = { }; + bless $self, $class; + return $self; +} + +sub add_to_index_queue { + my ( $self, $indexnumber, $op, $server, $oldRecord, $newRecord ) = @_; + my $dbh = C4::Context->dbh; +# lock the nozebra table : we will read index lines, update them in Perl process +# and write everything in 1 transaction. +# lock the table to avoid someone else overwriting what we are doing + $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE, auth_subfield_structure READ'); + my %result; # the result hash that will be built by deletion / add, and written on mySQL at the end, to improve speed + if ( $op eq 'specialUpdate' ) { + +# OK, we have to add or update the record +# 1st delete (virtually, in indexes), if record actually exists + if ($oldRecord) { + %result = _DelBiblioNoZebra( $indexnumber, $oldRecord, $server ); + } + +# ... add the record + %result = _AddBiblioNoZebra( $indexnumber, $newRecord, $server, %result ); + } else { + +# it's a deletion, delete the record... +# warn "DELETE the record $indexnumber on $server".$record->as_formatted; + %result = _DelBiblioNoZebra( $indexnumber, $oldRecord, $server ); + } + +# ok, now update the database... + my $sth = $dbh->prepare("UPDATE nozebra SET indexnumbers=? WHERE server=? AND indexname=? AND value=?"); + foreach my $key ( keys %result ) { + foreach my $index ( keys %{ $result{$key} } ) { + $sth->execute( $result{$key}->{$index}, $server, $key, $index ); + } + } + $dbh->do('UNLOCK TABLES'); +} + +sub get_indexes { + my $no_zebra_indexes = C4::Context->preference('NoZebraIndexes'); + my %indexes; + INDEX: foreach my $line ( split /['"],[\n\r]*/, $no_zebra_indexes ) { + $line =~ /(.*)=>(.*)/; + my $index = $1; # initial ' or " is removed afterwards + my $fields = $2; + $index =~ s/'|"|\s//g; + $fields =~ s/'|"|\s//g; + $indexes{$index} = $fields; + } + return %indexes; +} + +=head1 INTERNAL FUNCTIONS + +=head2 _DelBiblioNoZebra($biblionumber,$record,$server); + +function to delete a biblio in NoZebra indexes +This function does NOT delete anything in database : it reads all the indexes entries +that have to be deleted & delete them in the hash + +The SQL part is done either : + - after the Add if we are modifying a biblio (delete + add again) + - immediatly after this sub if we are doing a true deletion. + +$server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself + +=cut + +sub _DelBiblioNoZebra { + my ( $biblionumber, $record, $server ) = @_; + + # Get the indexes + my $dbh = C4::Context->dbh; + + # Get the indexes + my %index; + my $title; + if ( $server eq 'biblioserver' ) { + %index = get_indexes; + + # get title of the record (to store the 10 first letters with the index) + my ( $titletag, $titlesubfield ) = GetMarcFromKohaField( 'biblio.title', '' ); # FIXME: should be GetFrameworkCode($biblionumber) ?? + $title = lc( $record->subfield( $titletag, $titlesubfield ) ); + } else { + + # for authorities, the "title" is the $a mainentry + my ( $auth_type_tag, $auth_type_sf ) = C4::AuthoritiesMarc::get_auth_type_location(); + my $authref = GetAuthType( $record->subfield( $auth_type_tag, $auth_type_sf ) ); + warn "ERROR : authtype undefined for " . $record->as_formatted unless $authref; + $title = $record->subfield( $authref->{auth_tag_to_report}, 'a' ); + $index{'mainmainentry'} = $authref->{'auth_tag_to_report'} . 'a'; + $index{'mainentry'} = $authref->{'auth_tag_to_report'} . '*'; + $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}"; + } + + my %result; + + # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values + $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g; + + # limit to 10 char, should be enough, and limit the DB size + $title = substr( $title, 0, 10 ); + + #parse each field + my $sth2 = $dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?'); + foreach my $field ( $record->fields() ) { + + #parse each subfield + next if $field->tag < 10; + foreach my $subfield ( $field->subfields() ) { + my $tag = $field->tag(); + my $subfieldcode = $subfield->[0]; + my $indexed = 0; + + # check each index to see if the subfield is stored somewhere + # otherwise, store it in __RAW__ index + foreach my $key ( keys %index ) { + + # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode"; + if ( $index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/ ) { + $indexed = 1; + my $line = lc $subfield->[1]; + + # remove meaningless value in the field... + $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g; + + # ... and split in words + foreach ( split / /, $line ) { + next unless $_; # skip empty values (multiple spaces) + # if the entry is already here, do nothing, the biblionumber has already be removed + unless ( defined( $result{$key}->{$_} ) && ( $result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/ ) ) { + + # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing + $sth2->execute( $server, $key, $_ ); + my $existing_biblionumbers = $sth2->fetchrow; + + # it exists + if ($existing_biblionumbers) { + + # warn " existing for $key $_: $existing_biblionumbers"; + $result{$key}->{$_} = $existing_biblionumbers; + $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//; + } + } + } + } + } + + # the subfield is not indexed, store it in __RAW__ index anyway + unless ($indexed) { + my $line = lc $subfield->[1]; + $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g; + + # ... and split in words + foreach ( split / /, $line ) { + next unless $_; # skip empty values (multiple spaces) + # if the entry is already here, do nothing, the biblionumber has already be removed + unless ( $result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/ ) { + + # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing + $sth2->execute( $server, '__RAW__', $_ ); + my $existing_biblionumbers = $sth2->fetchrow; + + # it exists + if ($existing_biblionumbers) { + $result{'__RAW__'}->{$_} = $existing_biblionumbers; + $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//; + } + } + } + } + } + } + return %result; +} + +=head2 _AddBiblioNoZebra + + _AddBiblioNoZebra($biblionumber, $record, $server, %result); + +function to add a biblio in NoZebra indexes + +=cut + +sub _AddBiblioNoZebra { + my ( $biblionumber, $record, $server, %result ) = @_; + my $dbh = C4::Context->dbh; + + # Get the indexes + my %index; + my $title; + if ( $server eq 'biblioserver' ) { + %index = get_indexes; + + # get title of the record (to store the 10 first letters with the index) + my ( $titletag, $titlesubfield ) = GetMarcFromKohaField( 'biblio.title', '' ); # FIXME: should be GetFrameworkCode($biblionumber) ?? + $title = lc( $record->subfield( $titletag, $titlesubfield ) ); + } else { + + # warn "server : $server"; + # for authorities, the "title" is the $a mainentry + my ( $auth_type_tag, $auth_type_sf ) = C4::AuthoritiesMarc::get_auth_type_location(); + my $authref = GetAuthType( $record->subfield( $auth_type_tag, $auth_type_sf ) ); + warn "ERROR : authtype undefined for " . $record->as_formatted unless $authref; + $title = $record->subfield( $authref->{auth_tag_to_report}, 'a' ); + $index{'mainmainentry'} = $authref->{auth_tag_to_report} . 'a'; + $index{'mainentry'} = $authref->{auth_tag_to_report} . '*'; + $index{'auth_type'} = "${auth_type_tag}${auth_type_sf}"; + } + + # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values + $title =~ s/ |\.|,|;|\[|\]|\(|\)|\*|-|'|:|=|\r|\n//g; + + # limit to 10 char, should be enough, and limit the DB size + $title = substr( $title, 0, 10 ); + + #parse each field + my $sth2 = $dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?'); + foreach my $field ( $record->fields() ) { + + #parse each subfield + ###FIXME: impossible to index a 001-009 value with NoZebra + next if $field->tag < 10; + foreach my $subfield ( $field->subfields() ) { + my $tag = $field->tag(); + my $subfieldcode = $subfield->[0]; + my $indexed = 0; + + # warn "INDEXING :".$subfield->[1]; + # check each index to see if the subfield is stored somewhere + # otherwise, store it in __RAW__ index + foreach my $key ( keys %index ) { + + # warn "examining $key index : ".$index{$key}." for $tag $subfieldcode"; + if ( $index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/ ) { + $indexed = 1; + my $line = lc $subfield->[1]; + + # remove meaningless value in the field... + $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g; + + # ... and split in words + foreach ( split / /, $line ) { + next unless $_; # skip empty values (multiple spaces) + # if the entry is already here, improve weight + + # warn "managing $_"; + if ( exists $result{$key}->{$_} && $result{$key}->{"$_"} =~ /$biblionumber,\Q$title\E\-(\d+);/ ) { + my $weight = $1 + 1; + $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g; + $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;"; + } else { + + # get the value if it exist in the nozebra table, otherwise, create it + $sth2->execute( $server, $key, $_ ); + my $existing_biblionumbers = $sth2->fetchrow; + + # it exists + if ($existing_biblionumbers) { + $result{$key}->{"$_"} = $existing_biblionumbers; + my $weight = defined $1 ? $1 + 1 : 1; + $result{$key}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//g; + $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;"; + + # create a new ligne for this entry + } else { + + # warn "INSERT : $server / $key / $_"; + $dbh->do( 'INSERT INTO nozebra SET server=' . $dbh->quote($server) . ', indexname=' . $dbh->quote($key) . ',value=' . $dbh->quote($_) ); + $result{$key}->{"$_"} .= "$biblionumber,$title-1;"; + } + } + } + } + } + + # the subfield is not indexed, store it in __RAW__ index anyway + unless ($indexed) { + my $line = lc $subfield->[1]; + $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:|\r|\n/ /g; + + # ... and split in words + foreach ( split / /, $line ) { + next unless $_; # skip empty values (multiple spaces) + # if the entry is already here, improve weight + my $tmpstr = $result{'__RAW__'}->{"$_"} || ""; + if ( $tmpstr =~ /$biblionumber,\Q$title\E\-(\d+);/ ) { + my $weight = $1 + 1; + $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//; + $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;"; + } else { + + # get the value if it exist in the nozebra table, otherwise, create it + $sth2->execute( $server, '__RAW__', $_ ); + my $existing_biblionumbers = $sth2->fetchrow; + + # it exists + if ($existing_biblionumbers) { + $result{'__RAW__'}->{"$_"} = $existing_biblionumbers; + my $weight = ( $1 ? $1 : 0 ) + 1; + $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,\Q$title\E\-(\d+);//; + $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;"; + + # create a new ligne for this entry + } else { + $dbh->do( 'INSERT INTO nozebra SET server=' . $dbh->quote($server) . ', indexname="__RAW__",value=' . $dbh->quote($_) ); + $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-1;"; + } + } + } + } + } + } + return %result; +} + +1; +__END__ + +=head1 NAME + +Koha::Search::Engine::NoZebra - interface to deprecated NoZebra as the search engine for Koha + +=cut diff --git a/Koha/Search/Engine/Zebra.pm b/Koha/Search/Engine/Zebra.pm new file mode 100644 index 0000000..46f8b5c --- /dev/null +++ b/Koha/Search/Engine/Zebra.pm @@ -0,0 +1,257 @@ +package Koha::Search::Engine::Zebra; + +# Copyright 2011 C & P Bibliography Services +# +# 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 distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; + +use base qw(Koha::Search::Engine); + +sub new { + my $class = shift; + + my $self = { }; + bless $self, $class; + return $self; +} + +sub add_to_index_queue { + my ( $self, $indexnumber, $op, $server, $oldRecord, $newRecord ) = @_; + my $dbh = C4::Context->dbh; +# +# we use zebra, just fill zebraqueue table +# + my $check_sql = "SELECT COUNT(*) FROM zebraqueue + WHERE server = ? + AND biblio_auth_number = ? + AND operation = ? + AND done = 0"; + my $check_sth = $dbh->prepare_cached($check_sql); + $check_sth->execute( $server, $indexnumber, $op ); + my ($count) = $check_sth->fetchrow_array; + $check_sth->finish(); + if ( $count == 0 ) { + my $sth = $dbh->prepare("INSERT INTO zebraqueue (biblio_auth_number,server,operation) VALUES(?,?,?)"); + $sth->execute( $indexnumber, $server, $op ); + $sth->finish; + } +} + +sub get_indexes { + my @indexes = ( + # biblio indexes + 'ab', + 'Abstract', + 'acqdate', + 'allrecords', + 'an', + 'Any', + 'at', + 'au', + 'aub', + 'aud', + 'audience', + 'auo', + 'aut', + 'Author', + 'Author-in-order ', + 'Author-personal-bibliography', + 'Authority-Number', + 'authtype', + 'bc', + 'Bib-level', + 'biblionumber', + 'bio', + 'biography', + 'callnum', + 'cfn', + 'Chronological-subdivision', + 'cn-bib-source', + 'cn-bib-sort', + 'cn-class', + 'cn-item', + 'cn-prefix', + 'cn-suffix', + 'cpn', + 'Code-institution', + 'Conference-name', + 'Conference-name-heading', + 'Conference-name-see', + 'Conference-name-seealso', + 'Content-type', + 'Control-number', + 'copydate', + 'Corporate-name', + 'Corporate-name-heading', + 'Corporate-name-see', + 'Corporate-name-seealso', + 'ctype', + 'date-entered-on-file', + 'Date-of-acquisition', + 'Date-of-publication', + 'Dewey-classification', + 'EAN', + 'extent', + 'fic', + 'fiction', + 'Form-subdivision', + 'format', + 'Geographic-subdivision', + 'he', + 'Heading', + 'Heading-use-main-or-added-entry', + 'Heading-use-series-added-entry ', + 'Heading-use-subject-added-entry', + 'Host-item', + 'id-other', + 'Illustration-code', + 'ISBN', + 'isbn', + 'ISSN', + 'issn', + 'itemtype', + 'kw', + 'Koha-Auth-Number', + 'l-format', + 'language', + 'lc-card', + 'LC-card-number', + 'lcn', + 'llength', + 'ln', + 'Local-classification', + 'Local-number', + 'Match-heading', + 'Match-heading-see-from', + 'Material-type', + 'mc-itemtype', + 'mc-rtype', + 'mus', + 'name', + 'Music-number', + 'Name-geographic', + 'Name-geographic-heading', + 'Name-geographic-see', + 'Name-geographic-seealso', + 'nb', + 'Note', + 'notes', + 'ns', + 'nt', + 'pb', + 'Personal-name', + 'Personal-name-heading', + 'Personal-name-see', + 'Personal-name-seealso', + 'pl', + 'Place-publication', + 'pn', + 'popularity', + 'pubdate', + 'Publisher', + 'Record-control-number', + 'rcn', + 'Record-type', + 'rtype', + 'se', + 'See', + 'See-also', + 'sn', + 'Stock-number', + 'su', + 'Subject', + 'Subject-heading-thesaurus', + 'Subject-name-personal', + 'Subject-subdivision', + 'Summary', + 'Suppress', + 'su-geo', + 'su-na', + 'su-to', + 'su-ut', + 'ut', + 'UPC', + 'Term-genre-form', + 'Term-genre-form-heading', + 'Term-genre-form-see', + 'Term-genre-form-seealso', + 'ti', + 'Title', + 'Title-cover', + 'Title-series', + 'Title-host', + 'Title-uniform', + 'Title-uniform-heading', + 'Title-uniform-see', + 'Title-uniform-seealso', + 'totalissues', + 'yr', + + # items indexes + 'acqsource', + 'barcode', + 'bc', + 'branch', + 'ccode', + 'classification-source', + 'cn-sort', + 'coded-location-qualifier', + 'copynumber', + 'damaged', + 'datelastborrowed', + 'datelastseen', + 'holdingbranch', + 'homebranch', + 'issues', + 'item', + 'itemnumber', + 'itype', + 'Local-classification', + 'location', + 'lost', + 'materials-specified', + 'mc-ccode', + 'mc-itype', + 'mc-loc', + 'notforloan', + 'onloan', + 'price', + 'renewals', + 'replacementprice', + 'replacementpricedate', + 'reserves', + 'restricted', + 'stack', + 'stocknumber', + 'inv', + 'uri', + 'withdrawn', + + # subject related + ); + return \@indexes; +} + +1; +__END__ + +=head1 NAME + +Koha::Search::Engine::Zebra - interface to Zebra as the search engine for Koha + +=cut diff --git a/Koha/Utils.pm b/Koha/Utils.pm new file mode 100644 index 0000000..c3ab726 --- /dev/null +++ b/Koha/Utils.pm @@ -0,0 +1,119 @@ +package Koha::Utils; + +# Copyright 2011 C & P Bibliography Services +# +# 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 distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use C4::Context; + +use vars qw($VERSION @ISA @EXPORT); + +BEGIN { + our $VERSION = 3.01; + our $DEBUG = ($ENV{DEBUG}) ? 1 : 0; +} + +=head1 NAME + +Koha::Utils - Various utility functions for accessing a Koha instance's +configuration + +=head1 SYNOPSIS + + use Koha::Utils; + +=head1 DESCRIPTION + +Various high-level utility functions for getting information about a Koha +instance's configuration options, to complement the low-level functions in +Koha::Context. + + +=head1 FUNCTIONS + +=cut + +require Exporter; +@ISA = qw( Exporter ); +@EXPORT = qw( + &GetMarcFromKohaField + &GetAuthType +); + + + +=head2 GetMarcFromKohaField + + ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode); + +Returns the MARC fields & subfields mapped to the koha field +for the given frameworkcode + +=cut + +sub GetMarcFromKohaField { + my ( $kohafield, $frameworkcode ) = @_; + return 0, 0 unless $kohafield and defined $frameworkcode; + my $relations = C4::Context->marcfromkohafield; + return ( $relations->{$frameworkcode}->{$kohafield}->[0], $relations->{$frameworkcode}->{$kohafield}->[1] ); +} + +=head2 GetAuthType + + $result = &GetAuthType($authtypecode) + +If the authority type specified by C<$authtypecode> exists, +returns a hashref of the type's fields. If the type +does not exist, returns undef. + +=cut + +sub GetAuthType { + my ($authtypecode) = @_; + my $dbh=C4::Context->dbh; + my $sth; + if (defined $authtypecode){ # NOTE - in MARC21 framework, '' is a valid authority + # type (FIXME but why?) + $sth=$dbh->prepare("select * from auth_types where authtypecode=?"); + $sth->execute($authtypecode); + if (my $res = $sth->fetchrow_hashref) { + return $res; + } + } + return; +} + + +=head2 EXPORT + +GetMarcFromKohaField +GetAuthType + +=head1 SEE ALSO + +Koha::Context + +=head1 AUTHOR + +Jared Camins-Esakov, C & P Bibliography Services, Ejcamins@cpbibliography.comE + +=cut + +1; + +__END__ diff --git a/acqui/addorderiso2709.pl b/acqui/addorderiso2709.pl index 660d633..8dff50d 100755 --- a/acqui/addorderiso2709.pl +++ b/acqui/addorderiso2709.pl @@ -45,6 +45,7 @@ use C4::Dates; use C4::Suggestions; # GetSuggestion use C4::Branch; # GetBranches use C4::Members; +use Koha::Utils; my $input = new CGI; my ($template, $loggedinuser, $cookie) = get_template_and_user({ diff --git a/acqui/neworderempty.pl b/acqui/neworderempty.pl index ba856b2..4e0050b 100755 --- a/acqui/neworderempty.pl +++ b/acqui/neworderempty.pl @@ -87,6 +87,7 @@ use C4::Koha; use C4::Branch; # GetBranches use C4::Members; use C4::Search qw/FindDuplicate/; +use Koha::Utils; #needed for z3950 import: use C4::ImportBatch qw/GetImportRecordMarc SetImportRecordStatus/; diff --git a/authorities/authorities.pl b/authorities/authorities.pl index 2f82f5a..8808770 100755 --- a/authorities/authorities.pl +++ b/authorities/authorities.pl @@ -30,6 +30,7 @@ use Date::Calc qw(Today); use MARC::File::USMARC; use MARC::File::XML; use C4::Biblio; +use Koha::Utils; use vars qw( $tagslib); use vars qw( $authorised_values_sth); use vars qw( $is_a_modif ); diff --git a/authorities/blinddetail-biblio-search.pl b/authorities/blinddetail-biblio-search.pl index 7de7db3..35a8e34 100755 --- a/authorities/blinddetail-biblio-search.pl +++ b/authorities/blinddetail-biblio-search.pl @@ -46,6 +46,7 @@ use C4::Output; use CGI; use MARC::Record; use C4::Koha; +use Koha::Utils; my $query = new CGI; diff --git a/authorities/detail-biblio-search.pl b/authorities/detail-biblio-search.pl index 56a1a45..fa32655 100755 --- a/authorities/detail-biblio-search.pl +++ b/authorities/detail-biblio-search.pl @@ -47,6 +47,7 @@ use C4::Output; use CGI; use MARC::Record; use C4::Koha; +use Koha::Utils; # use C4::Biblio; # use C4::Catalogue; diff --git a/catalogue/MARCdetail.pl b/catalogue/MARCdetail.pl index 0490076..99fca98 100755 --- a/catalogue/MARCdetail.pl +++ b/catalogue/MARCdetail.pl @@ -58,6 +58,7 @@ use C4::Acquisition; use C4::Members; # to use GetMember use C4::Serials; #uses getsubscriptionsfrombiblionumber GetSubscriptionsFromBiblionumber use C4::Search; # enabled_staff_search_views +use Koha::Utils; my $query = new CGI; diff --git a/cataloguing/addbiblio.pl b/cataloguing/addbiblio.pl index e602bf8..6072546 100755 --- a/cataloguing/addbiblio.pl +++ b/cataloguing/addbiblio.pl @@ -35,6 +35,7 @@ use C4::Branch; # XXX subfield_is_koha_internal_p use C4::ClassSource; use C4::ImportBatch; use C4::Charset; +use Koha::Utils; use Date::Calc qw(Today); use MARC::File::USMARC; diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index a734d0f..6c3257a 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -31,6 +31,7 @@ use C4::Koha; # XXX subfield_is_koha_internal_p use C4::Branch; # XXX subfield_is_koha_internal_p use C4::ClassSource; use C4::Dates; +use Koha::Utils; use List::MoreUtils qw/any/; use MARC::File::XML; diff --git a/cataloguing/value_builder/barcode.pl b/cataloguing/value_builder/barcode.pl index c5e1fd3..02d8994 100755 --- a/cataloguing/value_builder/barcode.pl +++ b/cataloguing/value_builder/barcode.pl @@ -22,6 +22,7 @@ use warnings; no warnings 'redefine'; # otherwise loading up multiple plugins fills the log with subroutine redefine warnings use C4::Context; +use Koha::Utils; require C4::Dates; my $DEBUG = 0; diff --git a/cataloguing/value_builder/dateaccessioned.pl b/cataloguing/value_builder/dateaccessioned.pl index af1a285..8133669 100755 --- a/cataloguing/value_builder/dateaccessioned.pl +++ b/cataloguing/value_builder/dateaccessioned.pl @@ -19,6 +19,7 @@ use strict; #use warnings; FIXME - Bug 2505 +use Koha::Utils; =head1 diff --git a/circ/branchoverdues.pl b/circ/branchoverdues.pl index 5c1dcaf..9ea0a0e 100755 --- a/circ/branchoverdues.pl +++ b/circ/branchoverdues.pl @@ -28,6 +28,7 @@ use C4::Biblio; use C4::Koha; use C4::Debug; use C4::Branch; +use Koha::Utils; =head1 branchoverdues.pl diff --git a/installer/data/mysql/atomicupdate/bug_7430_add_searchengine_syspref b/installer/data/mysql/atomicupdate/bug_7430_add_searchengine_syspref new file mode 100644 index 0000000..c49bf66 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_7430_add_searchengine_syspref @@ -0,0 +1,8 @@ +#! /usr/bin/perl +use strict; +use warnings; +use C4::Context; +my $dbh=C4::Context->dbh; +my $searchengine = C4::Context->preference('NoZebra') ? 'NoZebra' : 'Zebra'; +$dbh->do("INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('SearchEngine','" . $searchengine . "','Chooses which search engine to use in Koha.','Zebra|NoZebra','Choice');"); +print "Upgrade done (Configured bug 7430, added new SearchEngine syspref)\n"; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref index 12075ec..aaf236c 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref @@ -1,6 +1,13 @@ Searching: Features: - + - pref: SearchEngine + - Use the + choices: + Zebra: Zebra + NoZebra: NoZebra + - search engine in Koha. + - - pref: NoZebra choices: yes: "Don't use" diff --git a/misc/batchImportMARCWithBiblionumbers.pl b/misc/batchImportMARCWithBiblionumbers.pl index 4acc02b..178541f 100755 --- a/misc/batchImportMARCWithBiblionumbers.pl +++ b/misc/batchImportMARCWithBiblionumbers.pl @@ -14,6 +14,7 @@ BEGIN { use C4::Context; use C4::Biblio; +use Koha::Utils; use MARC::Record; use MARC::File::USMARC; use MARC::File::XML; diff --git a/misc/batchRebuildBiblioTables.pl b/misc/batchRebuildBiblioTables.pl index ae4f54e..bc43528 100755 --- a/misc/batchRebuildBiblioTables.pl +++ b/misc/batchRebuildBiblioTables.pl @@ -16,6 +16,7 @@ BEGIN { use MARC::Record; use C4::Context; use C4::Biblio; +use Koha::Utils; use Time::HiRes qw(gettimeofday); use Getopt::Long; diff --git a/misc/migration_tools/22_to_30/missing090field.pl b/misc/migration_tools/22_to_30/missing090field.pl index bfa8576..db8c21a 100755 --- a/misc/migration_tools/22_to_30/missing090field.pl +++ b/misc/migration_tools/22_to_30/missing090field.pl @@ -15,6 +15,7 @@ BEGIN { use C4::Context; use C4::Biblio; +use Koha::Utils; use MARC::Record; use MARC::File::USMARC; diff --git a/misc/migration_tools/bulkmarcimport.pl b/misc/migration_tools/bulkmarcimport.pl index 4f738e8..942141f 100755 --- a/misc/migration_tools/bulkmarcimport.pl +++ b/misc/migration_tools/bulkmarcimport.pl @@ -17,6 +17,7 @@ use MARC::File::XML; use MARC::Record; use MARC::Batch; use MARC::Charset; +use Koha::Utils; use C4::Context; use C4::Biblio; diff --git a/misc/migration_tools/merge_authority.pl b/misc/migration_tools/merge_authority.pl index 8e09594..f578883 100755 --- a/misc/migration_tools/merge_authority.pl +++ b/misc/migration_tools/merge_authority.pl @@ -15,6 +15,7 @@ use C4::Context; use C4::Search; use C4::Biblio; use C4::AuthoritiesMarc; +use Koha::Utils; use Time::HiRes qw(gettimeofday); use Getopt::Long; diff --git a/misc/migration_tools/rebuild_nozebra.pl b/misc/migration_tools/rebuild_nozebra.pl index b6b82c5..7ea1468 100755 --- a/misc/migration_tools/rebuild_nozebra.pl +++ b/misc/migration_tools/rebuild_nozebra.pl @@ -2,8 +2,10 @@ use C4::Context; use Getopt::Long; +use C4::Search; use C4::Biblio; use C4::AuthoritiesMarc; +use Koha::Utils; use strict; #use warnings; FIXME - Bug 2505 @@ -76,7 +78,7 @@ $dbh->do("update systempreferences set value=1 where variable='NoZebra'"); $dbh->do("truncate nozebra"); -my %index = GetNoZebraIndexes(); +my %index = GetIndexes(); if (!%index || $sysprefs ) { if (C4::Context->preference('marcflavour') eq 'UNIMARC') { @@ -94,7 +96,7 @@ if (!%index || $sysprefs ) { 'subject' => '600*,601*,606*,610*', 'dewey' => '676a', 'host-item' => '995a,995c',\" where variable='NoZebraIndexes'"); - %index = GetNoZebraIndexes(); + %index = GetIndexes(); } elsif (C4::Context->preference('marcflavour') eq 'MARC21') { $dbh->do("UPDATE systempreferences SET value=\" 'title' => '130a,210a,222a,240a,243a,245a,245b,246a,246b,247a,247b,250a,250b,440a,830a', @@ -118,7 +120,7 @@ if (!%index || $sysprefs ) { 'collection' => '9528', \"WHERE variable='NoZebraIndexes'"); - %index = GetNoZebraIndexes(); + %index = GetIndexes(); } } $|=1; @@ -254,7 +256,7 @@ while (my ($authid) = $sth->fetchrow) { my %index; # for authorities, the "title" is the $a mainentry - my $authref = C4::AuthoritiesMarc::GetAuthType(C4::AuthoritiesMarc::GetAuthTypeCode($authid)); + my $authref = GetAuthType(C4::AuthoritiesMarc::GetAuthTypeCode($authid)); warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref; my $title = $record->subfield($authref->{auth_tag_to_report},'a'); diff --git a/misc/migration_tools/rebuild_zebra.pl b/misc/migration_tools/rebuild_zebra.pl index fbfd3af..dff0db0 100755 --- a/misc/migration_tools/rebuild_zebra.pl +++ b/misc/migration_tools/rebuild_zebra.pl @@ -10,6 +10,7 @@ use File::Path; use C4::Biblio; use C4::AuthoritiesMarc; use C4::Items; +use Koha::Utils; # # script that checks zebradir structure & create directories & mandatory files if needed diff --git a/opac/opac-MARCdetail.pl b/opac/opac-MARCdetail.pl index ffa0a6d..2cd574d 100755 --- a/opac/opac-MARCdetail.pl +++ b/opac/opac-MARCdetail.pl @@ -52,6 +52,7 @@ use MARC::Record; use C4::Biblio; use C4::Acquisition; use C4::Koha; +use Koha::Utils; my $query = new CGI; diff --git a/opac/opac-authoritiesdetail.pl b/opac/opac-authoritiesdetail.pl index 6610dfd..fa8a2d5 100755 --- a/opac/opac-authoritiesdetail.pl +++ b/opac/opac-authoritiesdetail.pl @@ -46,6 +46,7 @@ use C4::Output; use CGI; use MARC::Record; use C4::Koha; +use Koha::Utils; my $query = new CGI; diff --git a/serials/serials-edit.pl b/serials/serials-edit.pl index 9ecd09f..167740c 100755 --- a/serials/serials-edit.pl +++ b/serials/serials-edit.pl @@ -72,6 +72,7 @@ use C4::Koha; use C4::Output; use C4::Context; use C4::Serials; +use Koha::Utils; use List::MoreUtils qw/uniq/; my $query = CGI->new(); diff --git a/svc/bib b/svc/bib index 29121ca..1f3eee9 100755 --- a/svc/bib +++ b/svc/bib @@ -24,6 +24,7 @@ use warnings; use CGI; use C4::Auth qw/check_api_auth/; use C4::Biblio; +use Koha::Utils; use XML::Simple; my $query = new CGI; diff --git a/svc/new_bib b/svc/new_bib index b84eaea..5d02f70 100755 --- a/svc/new_bib +++ b/svc/new_bib @@ -26,6 +26,7 @@ use C4::Auth qw/check_api_auth/; use C4::Biblio; use XML::Simple; use C4::Charset; +use Koha::Utils; my $query = new CGI; binmode STDOUT, ":utf8"; diff --git a/t/db_dependent/lib/KohaTest/AuthoritiesMarc.pm b/t/db_dependent/lib/KohaTest/AuthoritiesMarc.pm index 4938ccf..ca6ea6b 100644 --- a/t/db_dependent/lib/KohaTest/AuthoritiesMarc.pm +++ b/t/db_dependent/lib/KohaTest/AuthoritiesMarc.pm @@ -23,7 +23,6 @@ sub methods : Test( 1 ) { ModAuthority GetAuthorityXML GetAuthority - GetAuthType FindDuplicateAuthority BuildSummary BuildUnimarcHierarchies diff --git a/t/db_dependent/lib/KohaTest/Biblio/ModBiblio.pm b/t/db_dependent/lib/KohaTest/Biblio/ModBiblio.pm index 5b29ea8..41458b2 100644 --- a/t/db_dependent/lib/KohaTest/Biblio/ModBiblio.pm +++ b/t/db_dependent/lib/KohaTest/Biblio/ModBiblio.pm @@ -8,6 +8,7 @@ use Test::More; use C4::Biblio; use C4::Items; +use Koha::Utils; =head2 STARTUP METHODS diff --git a/t/db_dependent/lib/KohaTest/ImportBatch/BatchStageCommitRevert.pm b/t/db_dependent/lib/KohaTest/ImportBatch/BatchStageCommitRevert.pm index e03ee1f..fb53dfe 100644 --- a/t/db_dependent/lib/KohaTest/ImportBatch/BatchStageCommitRevert.pm +++ b/t/db_dependent/lib/KohaTest/ImportBatch/BatchStageCommitRevert.pm @@ -9,6 +9,7 @@ use Test::More; use C4::ImportBatch; use C4::Matcher; use C4::Biblio; +use Koha::Utils; # define test records for various batches sub startup_60_make_test_records : Test( startup ) { diff --git a/tools/batchMod.pl b/tools/batchMod.pl index 94cfa69..9febd9c 100755 --- a/tools/batchMod.pl +++ b/tools/batchMod.pl @@ -33,6 +33,7 @@ use C4::BackgroundJob; use C4::ClassSource; use C4::Dates; use C4::Debug; +use Koha::Utils; use MARC::File::XML; my $input = new CGI; diff --git a/tools/export.pl b/tools/export.pl index 4b3e3f5..1f2bd05 100755 --- a/tools/export.pl +++ b/tools/export.pl @@ -25,6 +25,7 @@ use C4::Biblio; # GetMarcBiblio GetXmlBiblio use CGI; use C4::Koha; # GetItemTypes use C4::Branch; # GetBranches +use Koha::Utils; my $query = new CGI; my $op=$query->param("op") || ''; -- 1.7.2.5