From bc05b5d163ae1aabd6fad813a8cf8e784ea6e90b Mon Sep 17 00:00:00 2001 From: Jared Camins-Esakov Date: Sat, 2 Jun 2012 13:32:25 -0400 Subject: [PATCH] Bug 7417: Include see from references in bibliographic searches This patch adds the Koha::Indexer::RecordNormalizer and Koha::Indexer::MARC::RecordNormalizer::EmbedSeeFromHeadings packages to enable the inclusion of alternate forms of headings in bibliographic searches. When the new syspref IncludeSeeFromInSearches is turned on (default is off) rebuild_zebra.pl will insert see from headings from authority records into bibliographic records when indexing, so that a search on an obsolete term will turn up relevant records. To test: 1) Enable IncludeSeeFromInSearches 2) Add a heading that has an alternate form to a record (for example, "Cooking" has the alternate form "Cookery," if you have authority records from LC) 3) Index the zebraqueue (or reindex if you haven't indexed your system yet) 4) Confirm that if you search for "Cookery" you get the record you just modified Signed-off-by: Jared Camins-Esakov Rebased on master 5 August 2012 Signed-off-by: Jared Camins-Esakov Rebased on master 11 September 2012 Signed-off-by: Katrin Fischer Also checked: - Verified database update works correctly - Checked system preference and its description - Checked staff/opac detail pages with feature on/off - Checked staff/opac search facets - Downloaded and tested records in various formats - Tried different searches for 'see from' entries of authorities - Ran all unit tests No problems found. --- C4/AuthoritiesMarc.pm | 16 +- C4/Search.pm | 3 +- Koha/Authority.pm | 92 +++++++++ Koha/Filter/MARC/EmbedSeeFromHeadings.pm | 102 ++++++++++ Koha/Filter/MARC/Null.pm | 55 ++++++ Koha/RecordProcessor.pm | 183 ++++++++++++++++++ Koha/RecordProcessor/Base.pm | 133 +++++++++++++ Koha/SearchEngine/Solr/Index.pm | 6 + installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 7 + .../modules/admin/preferences/searching.pref | 6 + .../en/xslt/MARC21slim2intranetResults.xsl | 6 +- .../en/xslt/NORMARCslim2intranetResults.xsl | 6 +- .../prog/en/xslt/MARC21slim2OPACResults.xsl | 6 +- .../prog/en/xslt/NORMARCslim2OPACResults.xsl | 6 +- .../process_record_through_filter.pl | 18 ++ misc/migration_tools/rebuild_zebra.pl | 4 + t/RecordProcessor.t | 80 ++++++++ t/db_dependent/Koha_Authority.t | 66 +++++++ .../RecordProcessor_EmbedSeeFromHeadings.t | 66 +++++++ 20 files changed, 836 insertions(+), 26 deletions(-) create mode 100644 Koha/Authority.pm create mode 100644 Koha/Filter/MARC/EmbedSeeFromHeadings.pm create mode 100644 Koha/Filter/MARC/Null.pm create mode 100644 Koha/RecordProcessor.pm create mode 100644 Koha/RecordProcessor/Base.pm create mode 100755 misc/maintenance/process_record_through_filter.pl create mode 100755 t/RecordProcessor.t create mode 100755 t/db_dependent/Koha_Authority.t create mode 100755 t/db_dependent/RecordProcessor_EmbedSeeFromHeadings.t diff --git a/C4/AuthoritiesMarc.pm b/C4/AuthoritiesMarc.pm index f7bb726681..ba3c41b727 100644 --- a/C4/AuthoritiesMarc.pm +++ b/C4/AuthoritiesMarc.pm @@ -26,6 +26,7 @@ use C4::AuthoritiesMarc::MARC21; use C4::AuthoritiesMarc::UNIMARC; use C4::Charset; use C4::Log; +use Koha::Authority; use vars qw($VERSION @ISA @EXPORT); @@ -851,19 +852,8 @@ Returns MARC::Record of the authority passed in parameter. sub GetAuthority { my ($authid)=@_; - my $dbh=C4::Context->dbh; - my $sth=$dbh->prepare("select authtypecode, marcxml from auth_header where authid=?"); - $sth->execute($authid); - my ($authtypecode, $marcxml) = $sth->fetchrow; - my $record=eval {MARC::Record->new_from_xml(StripNonXmlChars($marcxml),'UTF-8', - (C4::Context->preference("marcflavour") eq "UNIMARC"?"UNIMARCAUTH":C4::Context->preference("marcflavour")))}; - return undef if ($@); - $record->encoding('UTF-8'); - if (C4::Context->preference("marcflavour") eq "MARC21") { - my ($auth_type_tag, $auth_type_subfield) = get_auth_type_location($authtypecode); - C4::AuthoritiesMarc::MARC21::fix_marc21_auth_type_location($record, $auth_type_tag, $auth_type_subfield); - } - return ($record); + my $authority = Koha::Authority->get_from_authid($authid); + return ($authority->record); } =head2 GetAuthType diff --git a/C4/Search.pm b/C4/Search.pm index 3edf118557..d9b53ac1ed 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -477,7 +477,8 @@ sub getRecords { # avoid first line my $tag_num = substr($tag, 0, 3); my $letters = substr($tag, 3); - my $field_pattern = '\n' . $tag_num . ' ([^\n]+)'; + my $field_pattern = '\n' . $tag_num . ' ([^z][^\n]+)'; + $field_pattern = '\n' . $tag_num . ' ([^\n]+)' if (int($tag_num) < 10); my @field_tokens = ( $render_record =~ /$field_pattern/g ) ; foreach my $field_token (@field_tokens) { my @subf = ( $field_token =~ /\$([a-zA-Z0-9]) ([^\$]+)/g ); diff --git a/Koha/Authority.pm b/Koha/Authority.pm new file mode 100644 index 0000000000..b64f8ded2b --- /dev/null +++ b/Koha/Authority.pm @@ -0,0 +1,92 @@ +package Koha::Authority; + +# Copyright 2012 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::Authority - class to encapsulate authority records in Koha + +=head1 SYNOPSIS + +Object-oriented class that encapsulates authority records in Koha. + +=head1 DESCRIPTION + +Authority data. + +=cut + +use strict; +use warnings; +use C4::Context; +use MARC::Record; +use MARC::File::XML; +use C4::Charset; + +use base qw(Class::Accessor); + +__PACKAGE__->mk_accessors(qw( authid authtype record marcflavour )); + +=head2 new + + my $auth = Koha::Authority->new($record); + +Create a new Koha::Authority object based on the provided record. + +=cut +sub new { + my $class = shift; + my $record = shift; + + my $self = $class->SUPER::new( { record => $record }); + + bless $self, $class; + return $self; +} + +=head2 get_from_authid + + my $auth = Koha::Authority->get_from_authid($authid); + +Create the Koha::Authority object associated with the provided authid. + +=cut +sub get_from_authid { + my $class = shift; + my $authid = shift; + my $marcflavour = C4::Context->preference("marcflavour"); + + my $dbh=C4::Context->dbh; + my $sth=$dbh->prepare("select authtypecode, marcxml from auth_header where authid=?"); + $sth->execute($authid); + my ($authtypecode, $marcxml) = $sth->fetchrow; + my $record=eval {MARC::Record->new_from_xml(StripNonXmlChars($marcxml),'UTF-8', + (C4::Context->preference("marcflavour") eq "UNIMARC"?"UNIMARCAUTH":C4::Context->preference("marcflavour")))}; + return undef if ($@); + $record->encoding('UTF-8'); + + my $self = $class->SUPER::new( { authid => $authid, + marcflavour => $marcflavour, + authtype => $authtypecode, + record => $record }); + + bless $self, $class; + return $self; +} + +1; diff --git a/Koha/Filter/MARC/EmbedSeeFromHeadings.pm b/Koha/Filter/MARC/EmbedSeeFromHeadings.pm new file mode 100644 index 0000000000..ea7e38b2dd --- /dev/null +++ b/Koha/Filter/MARC/EmbedSeeFromHeadings.pm @@ -0,0 +1,102 @@ +package Koha::Filter::MARC::EmbedSeeFromHeadings; + +# Copyright 2012 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::Filter::MARC::EmbedSeeFromHeadings - embeds see from headings into MARC for indexing + +=head1 SYNOPSIS + + +=head1 DESCRIPTION + +Filter to embed see from headings into MARC records. + +=cut + +use strict; +use warnings; +use Carp; +use Koha::Authority; + +use base qw(Koha::RecordProcessor::Base); +our $NAME = 'EmbedSeeFromHeadings'; +our $VERSION = '1.0'; + +=head2 filter + + my $newrecord = $filter->filter($record); + my $newrecords = $filter->filter(\@records); + +Embed see from headings into the specified record(s) and return the result. +In order to differentiate added headings from actual headings, a 'z' is +put in the first indicator. + +=cut +sub filter { + my $self = shift; + my $record = shift; + my $newrecord; + + return undef unless defined $record; + + if (ref $record eq 'ARRAY') { + my @recarray; + foreach my $thisrec (@$record) { + push @recarray, _processrecord($thisrec); + } + $newrecord = \@recarray; + } elsif (ref $record eq 'MARC::Record') { + $newrecord = _processrecord($record); + } + + return $newrecord; +} + +sub _processrecord { + my $record = shift; + + foreach my $field ( $record->fields() ) { + next if $field->is_control_field(); + my $authid = $field->subfield('9'); + + next unless $authid; + + my $authority = Koha::Authority->get_from_authid($authid); + next unless $authority; + my $auth_marc = $authority->record; + my @seefrom = $auth_marc->field('4..'); + my @newfields; + foreach my $authfield (@seefrom) { + my $tag = substr($field->tag(), 0, 1) . substr($authfield->tag(), 1, 2); + my $newfield = MARC::Field->new($tag, + 'z', + $authfield->indicator(2) || ' ', + '9' => '1'); + foreach my $sub ($authfield->subfields()) { + my ($code,$val) = @$sub; + $newfield->add_subfields( $code => $val ); + } + $newfield->delete_subfield( code => '9' ); + push @newfields, $newfield if (scalar($newfield->subfields()) > 0); + } + $record->append_fields(@newfields); + } + return $record; +} diff --git a/Koha/Filter/MARC/Null.pm b/Koha/Filter/MARC/Null.pm new file mode 100644 index 0000000000..578781c7c3 --- /dev/null +++ b/Koha/Filter/MARC/Null.pm @@ -0,0 +1,55 @@ +package Koha::Filter::MARC::Null; + +# Copyright 2012 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::Filter::MARC::Null - an example filter that does nothing but allow us to run tests + +=head1 SYNOPSIS + + +=head1 DESCRIPTION + +Filter to allow us to run unit tests and regression tests against the +RecordProcessor. + +=cut + +use strict; +use warnings; +use Carp; + +use base qw(Koha::RecordProcessor::Base); +our $NAME = 'Null'; +our $VERSION = '1.0'; + +=head2 filter + + my $newrecord = $filter->filter($record); + my $newrecords = $filter->filter(\@records); + +Return the original record. + +=cut +sub filter { + my $self = shift; + my $record = shift; + + return $record; +} diff --git a/Koha/RecordProcessor.pm b/Koha/RecordProcessor.pm new file mode 100644 index 0000000000..3d4e1bf6a6 --- /dev/null +++ b/Koha/RecordProcessor.pm @@ -0,0 +1,183 @@ +package Koha::RecordProcessor; + +# Copyright 2012 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::RecordProcessor - Dispatcher class for record normalization + +=head1 SYNOPSIS + + use Koha::RecordProcessor; + my $normalizer = Koha::RecordProcessor(%params); + $normalizer->process($record) + +=head1 DESCRIPTION + +Dispatcher class for record normalization. RecordProcessors must +extend Koha::RecordProcessor::Base, be in the Koha::Filter namespace, +and provide the following methods: + +B - apply the filter and return the result. $record +may be either a scalar or an arrayref, and the return result will be +the same type. + +These methods may be overriden: + +B - initialize the filter + +B - destroy the filter + +These methods should not be overridden unless you are very sure of what +you are doing: + +B - create a new filter object + +Note that the RecordProcessor will not clone the record that is +passed in. If you do not want to change the original MARC::Record +object (or whatever type of object you are passing in), you must +clone it I to passing it off to the RecordProcessor. + +=head1 FUNCTIONS + +=cut + +use strict; +use warnings; +use Module::Load::Conditional qw(can_load); +use Module::Pluggable::Object; + +use base qw(Class::Accessor); + +__PACKAGE__->mk_accessors(qw( schema filters options record )); + +=head2 new + + my $normalizer = Koha::RecordProcessor->new(%params); + +Create a new normalizer. Available parameters are: + +=over 8 + +=item B + +Which metadata schema is in use. At the moment the only supported schema +is 'MARC'. + +=item B + +What filter(s) to use. This must be an arrayref to a list of filters. Filters +can be specified either with a complete class path, or, if they are in the +Koha::Filter::${schema} namespace, as only the filter name, and +"Koha::Filter::${schema}" will be prepended to it before the filter is loaded. + +=back + +=cut +sub new { + my $class = shift; + my $param = shift; + + + my $schema = $param->{schema} || 'MARC'; + my $options = $param->{options} || ''; + my @filters = ( ); + + foreach my $filter ($param->{filters}) { + next unless $filter; + my $filter_module = $filter =~ m/:/ ? $filter : "Koha::Filter::${schema}::${filter}"; + if (can_load( modules => { $filter_module => undef } )) { + my $object = $filter_module->new(); + $filter_module->initialize($param); + push @filters, $object; + } + } + + my $self = $class->SUPER::new( { schema => $schema, + filters => \@filters, + options => $options }); + bless $self, $class; + return $self; +} + +=head2 bind + + $normalizer->bind($record) + +Bind a normalizer to a particular record. + +=cut +sub bind { + my $self = shift; + my $record = shift; + + $self->{record} = $record; + return; +} + +=head2 process + + my $newrecord = $normalizer->process([$record]) + +Run the record(s) through the normalization pipeline. If $record is +not specified, process the record the normalizer is bound to. +Note that $record may be either a scalar or an arrayref, and the +return value will be of the same type. + +=cut +sub process { + my $self = shift; + my $record = shift || $self->record; + + return unless defined $record; + + my $newrecord = $record; + + foreach my $filterobj (@{$self->filters}) { + next unless $filterobj; + $newrecord = $filterobj->filter($newrecord); + } + + return $newrecord; +} + +sub DESTROY { + my $self = shift; + + foreach my $filterobj (@{$self->filters}) { + $filterobj->destroy(); + } +} + +=head2 AvailableFilters + + my @available_filters = Koha::RecordProcessor::AvailableFilters([$schema]); + +Get a list of available filters. Optionally specify the metadata schema. +At present only MARC is supported as a schema. + +=cut +sub AvailableFilters { + my $schema = pop || ''; + my $path = 'Koha::Filter'; + $path .= "::$schema" if ($schema eq 'MARC'); + my $finder = Module::Pluggable::Object->new(search_path => $path); + return $finder->plugins; +} + +1; diff --git a/Koha/RecordProcessor/Base.pm b/Koha/RecordProcessor/Base.pm new file mode 100644 index 0000000000..00bc62398d --- /dev/null +++ b/Koha/RecordProcessor/Base.pm @@ -0,0 +1,133 @@ +package Koha::RecordProcessor::Base; + +# Copyright 2012 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::RecordProcessor::Base - Base class for RecordProcessor filters + +=head1 SYNOPSIS + + use base qw(Koha::RecordProcessor::Base); + +=head1 DESCRIPTION + +Base class for record normalizer filters. RecordProcessors must +provide the following methods: + +B - apply the filter and return the result. $record +may be either a scalar or an arrayref, and the return result will be +the same type. + +The following variables must be defined in each filter: + our $NAME ='Filter'; + our $VERSION = '1.0'; + +These methods may be overriden: + +B - initialize the filter + +B - destroy the filter + +These methods should not be overridden unless you are very sure of what +you are doing: + +B - create a new filter object + +Note that the RecordProcessor will not clone the record that is +passed in. If you do not want to change the original MARC::Record +object (or whatever type of object you are passing in), you must +clone it I to passing it off to the RecordProcessor. + +=head1 FUNCTIONS + +=cut + +use strict; +use warnings; + +use base qw(Class::Accessor); + +__PACKAGE__->mk_ro_accessors(qw( name version )); +__PACKAGE__->mk_accessors(qw( params )); +our $NAME = 'Base'; +our $VERSION = '1.0'; + + +=head2 new + + my $filter = Koha::RecordProcessor::Base->new; + +Create a new filter; + +=cut +sub new { + my $class = shift; + + my $self = $class->SUPER::new( { });#name => $class->NAME, + #version => $class->VERSION }); + + bless $self, $class; + return $self; +} + + +=head2 initialize + + $filter->initalize(%params); + +Initialize a filter using the specified parameters. + +=cut +sub initialize { + my $self = shift; + my $params = shift; + + #$self->params = $params; + + return $self; +} + + +=head2 destroy + + $filter->destroy(); + +Destroy the filter. + +=cut +sub destroy { + my $self = shift; + return; +} + +=head2 filter + + my $newrecord = $filter->filter($record); + my $newrecords = $filter->filter(\@records); + +Filter the specified record(s) and return the result. + +=cut +sub filter { + my $self = shift; + my $record = shift; + return $record; +} + +1; diff --git a/Koha/SearchEngine/Solr/Index.pm b/Koha/SearchEngine/Solr/Index.pm index fd7c3d78d0..6fa3242cf3 100644 --- a/Koha/SearchEngine/Solr/Index.pm +++ b/Koha/SearchEngine/Solr/Index.pm @@ -9,6 +9,7 @@ use List::MoreUtils qw(uniq); use Koha::SearchEngine::Solr; use C4::AuthoritiesMarc; use C4::Biblio; +use Koha::RecordProcessor; has searchengine => ( is => 'rw', @@ -39,6 +40,11 @@ sub index_record { $record = GetAuthority( $id ) if $recordtype eq "authority"; $record = GetMarcBiblio( $id ) if $recordtype eq "biblio"; + if ($record_type eq 'biblio' && C4::Context->preference('IncludeSeeFromInSearches')) { + my $normalizer = Koha::RecordProcessor->new( { filters => 'EmbedSeeFromHeadings' } ); + $record = $normalizer->process($record); + } + next unless ( $record ); my $index_values = { diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index ef6cdb38c0..33efb7878a 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -373,3 +373,4 @@ INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ( INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AgeRestrictionMarker','','Markers for age restriction indication, e.g. FSK|PEGI|Age|',NULL,'free'); INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('AgeRestrictionOverride',0,'Allow staff to check out an item with age restriction.',NULL,'YesNo'); INSERT INTO systempreferences (variable,value,explanation,type) VALUES('DidYouMeanFromAuthorities','0','Suggest searches based on authority file.','YesNo'); +INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('IncludeSeeFromInSearches','0','','Include see-from references in searches.','YesNo'); diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index a5cc4f27ad..bb4fb96aca 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -5729,6 +5729,13 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.09.00.040"; +if (C4::Context->preference("Version") < TransformToNum($DBversion)) { + $dbh->do("INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('IncludeSeeFromInSearches','0','','Include see-from references in searches.','YesNo');"); + print "Upgrade to $DBversion done (Add IncludeSeeFromInSearches system preference)\n"; + SetVersion ($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) 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 ce641720a1..3128ad6b49 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 @@ -83,6 +83,12 @@ Searching: yes: Suggest no: "Don't suggest" - alternate searches based on data in the authority file. + - pref: IncludeSeeFromInSearches + default: 0 + choices: + yes: Include + no: "Don't include" + - "see from (non-preferred form) headings in bibliographic searches. Please note: you will need to reindex your bibliographic database when changing this preference." Search Form: - - Show tabs in OPAC and staff-side advanced search for limiting searches on the diff --git a/koha-tmpl/intranet-tmpl/prog/en/xslt/MARC21slim2intranetResults.xsl b/koha-tmpl/intranet-tmpl/prog/en/xslt/MARC21slim2intranetResults.xsl index de7c1554bb..3714dab6cc 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/xslt/MARC21slim2intranetResults.xsl +++ b/koha-tmpl/intranet-tmpl/prog/en/xslt/MARC21slim2intranetResults.xsl @@ -336,7 +336,7 @@

by - + @@ -351,7 +351,7 @@ . ; - + @@ -365,7 +365,7 @@ ; - + diff --git a/koha-tmpl/intranet-tmpl/prog/en/xslt/NORMARCslim2intranetResults.xsl b/koha-tmpl/intranet-tmpl/prog/en/xslt/NORMARCslim2intranetResults.xsl index 373f482173..5ee95ffee2 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/xslt/NORMARCslim2intranetResults.xsl +++ b/koha-tmpl/intranet-tmpl/prog/en/xslt/NORMARCslim2intranetResults.xsl @@ -283,7 +283,7 @@

av - + @@ -298,7 +298,7 @@ . ; - + @@ -312,7 +312,7 @@ ; - + diff --git a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl b/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl index aaa1772685..a5246974fd 100644 --- a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl +++ b/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl @@ -450,7 +450,7 @@ by - + . @@ -461,7 +461,7 @@ - + -- @@ -477,7 +477,7 @@ - + -- diff --git a/koha-tmpl/opac-tmpl/prog/en/xslt/NORMARCslim2OPACResults.xsl b/koha-tmpl/opac-tmpl/prog/en/xslt/NORMARCslim2OPACResults.xsl index 36f81efbb6..907a82f77f 100644 --- a/koha-tmpl/opac-tmpl/prog/en/xslt/NORMARCslim2OPACResults.xsl +++ b/koha-tmpl/opac-tmpl/prog/en/xslt/NORMARCslim2OPACResults.xsl @@ -325,7 +325,7 @@ av - + . @@ -336,7 +336,7 @@ - + . @@ -347,7 +347,7 @@ - + . diff --git a/misc/maintenance/process_record_through_filter.pl b/misc/maintenance/process_record_through_filter.pl new file mode 100755 index 0000000000..3b3e537208 --- /dev/null +++ b/misc/maintenance/process_record_through_filter.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl + +# This script is intended for testing RecordProcessor filters. To use it +# run the script like so: +# > perl process_record_through_filter.pl ${BIBLIONUMBER} ${FILTER} + +use strict; +use warnings; +use Koha::RecordProcessor; +use Data::Dumper; +use C4::Biblio; + +my $record = GetMarcBiblio($ARGV[0]); + +print "Before: " . $record->as_formatted() . "\n"; +my $processor = Koha::RecordProcessor->new( { filters => ( $ARGV[1] ) }); +$record = $processor->process($record); +print "After : " . $record->as_formatted() . "\n"; diff --git a/misc/migration_tools/rebuild_zebra.pl b/misc/migration_tools/rebuild_zebra.pl index 1621e84b9b..e11817d453 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::RecordProcessor; # # script that checks zebradir structure & create directories & mandatory files if needed @@ -497,6 +498,9 @@ sub get_corrected_marc_record { fix_leader($marc); if ($record_type eq 'authority') { fix_authority_id($marc, $record_number); + } elsif ($record_type eq 'biblio' && C4::Context->preference('IncludeSeeFromInSearches')) { + my $normalizer = Koha::RecordProcessor->new( { filters => 'EmbedSeeFromHeadings' } ); + $marc = $normalizer->process($marc); } if (C4::Context->preference("marcflavour") eq "UNIMARC") { fix_unimarc_100($marc); diff --git a/t/RecordProcessor.t b/t/RecordProcessor.t new file mode 100755 index 0000000000..32acc6bb6d --- /dev/null +++ b/t/RecordProcessor.t @@ -0,0 +1,80 @@ +#!/usr/bin/perl + +# Copyright 2012 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 File::Spec; +use MARC::Record; + +use Test::More; + +BEGIN { + use_ok('Koha::RecordProcessor'); +} + +my $isbn = '0590353403'; +my $title = 'Foundation'; +my $marc_record=MARC::Record->new; +my $field = MARC::Field->new('020','','','a' => $isbn); +$marc_record->append_fields($field); +$field = MARC::Field->new('245','','','a' => $title); +$marc_record->append_fields($field); + + +my $filterdir = File::Spec->rel2abs('Koha/Filter') . '/MARC'; + +opendir(my $dh, $filterdir); +my @installed_filters = map { ( /\.pm$/ && -f "$filterdir/$_" && s/\.pm$// ) ? "Koha::Filters::MARC::$_" : () } readdir($dh); +my @available_filters = Koha::RecordProcessor::AvailableFilters(); + +foreach my $filter (@installed_filters) { + ok(grep($filter, @available_filters), "Found filter $filter"); +} + +my $marc_filters = grep (/MARC/, @available_filters); +is(scalar Koha::RecordProcessor::AvailableFilters('MARC'), $marc_filters, 'Retrieved list of MARC filters'); + +my $processor = Koha::RecordProcessor->new( { filters => ( 'ABCD::EFGH::IJKL' ) } ); + +is(ref($processor), 'Koha::RecordProcessor', 'Created record processor with invalid filter'); + +is($processor->process($marc_record), $marc_record, 'Process record with empty processor'); + +$processor = Koha::RecordProcessor->new( { filters => ( 'Null' ) } ); +is(ref($processor->filters->[0]), 'Koha::Filter::MARC::Null', 'Created record processor with implicitly scoped Null filter'); + +$processor = Koha::RecordProcessor->new( { filters => ( 'Koha::Filter::MARC::Null' ) } ); +is(ref($processor->filters->[0]), 'Koha::Filter::MARC::Null', 'Created record processor with explicitly scoped Null filter'); + +is($processor->process($marc_record), $marc_record, 'Process record'); + +$processor->bind($marc_record); + +is($processor->record, $marc_record, 'Bound record to processor'); + +is($processor->process(), $marc_record, 'Filter bound record'); + +eval { + $processor = Koha::RecordProcessor->new( { filters => ( 'Koha::Filter::MARC::Null' ) } ); + undef $processor; +}; + +ok(!$@, 'Destroyed processor successfully'); + +done_testing(); diff --git a/t/db_dependent/Koha_Authority.t b/t/db_dependent/Koha_Authority.t new file mode 100755 index 0000000000..dc577744df --- /dev/null +++ b/t/db_dependent/Koha_Authority.t @@ -0,0 +1,66 @@ +#!/usr/bin/perl + +# Copyright 2012 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 Test::More; + +BEGIN { + use_ok('Koha::Authority'); +} + +my $record = MARC::Record->new; + +$record->add_fields( + [ '001', '1234' ], + [ '150', ' ', ' ', a => 'Cooking' ], + [ '450', ' ', ' ', a => 'Cookery' ], + ); +my $authority = Koha::Authority->new($record); + +is(ref($authority), 'Koha::Authority', 'Created valid Koha::Authority object'); + +is_deeply($authority->record, $record, 'Saved record'); + +SKIP: +{ + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare("SELECT authid FROM auth_header LIMIT 1;"); + $sth->execute(); + + my $authid; + for my $row ($sth->fetchrow_hashref) { + $authid = $row->{'authid'}; + } + skip 'No authorities', 3 unless $authid; + $authority = Koha::Authority->get_from_authid($authid); + + is(ref($authority), 'Koha::Authority', 'Retrieved valid Koha::Authority object'); + + is($authority->authid, $authid, 'Object authid is correct'); + + is($authority->record->field('001')->data(), $authid, 'Retrieved correct record'); + + $authority = Koha::Authority->get_from_authid('alphabetsoup'); + is($authority, undef, 'No invalid record is retrieved'); +} + +done_testing(); diff --git a/t/db_dependent/RecordProcessor_EmbedSeeFromHeadings.t b/t/db_dependent/RecordProcessor_EmbedSeeFromHeadings.t new file mode 100755 index 0000000000..4742983085 --- /dev/null +++ b/t/db_dependent/RecordProcessor_EmbedSeeFromHeadings.t @@ -0,0 +1,66 @@ +#!/usr/bin/perl + +# Copyright 2012 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 File::Spec; +use MARC::Record; +use Koha::Authority; + +use Test::More; +use Test::MockModule; + +BEGIN { + use_ok('Koha::RecordProcessor'); +} + +my $module = new Test::MockModule('MARC::Record'); +$module->mock('new_from_xml', sub { + my $record = MARC::Record->new; + + $record->add_fields( + [ '001', '1234' ], + [ '150', ' ', ' ', a => 'Cooking' ], + [ '450', ' ', ' ', a => 'Cookery' ], + ); + + return $record; +}); + +my $bib = MARC::Record->new; +$bib->add_fields( + [ '245', '0', '4', a => 'The Ifrane cookbook' ], + [ '650', ' ', ' ', a => 'Cooking', 9 => '1234' ] + ); + +my $resultbib = MARC::Record->new; +$resultbib->add_fields( + [ '245', '0', '4', a => 'The Ifrane cookbook' ], + [ '650', ' ', ' ', a => 'Cooking', 9 => '1234' ], + [ '650', 'z', ' ', a => 'Cookery' ] + ); + +my $processor = Koha::RecordProcessor->new( { filters => ( 'EmbedSeeFromHeadings' ) } ); +is(ref($processor), 'Koha::RecordProcessor', 'Created record processor'); + +my $result = $processor->process($bib); + +is_deeply($result, $resultbib, 'Inserted see-from heading to record'); + +done_testing(); -- 2.39.5