From 0cc5abc486009549f5cf683a1bbbbf27f72a1d61 Mon Sep 17 00:00:00 2001
From: Jesse Weaver <jweaver@bywatersolutions.com>
Date: Mon, 22 Feb 2016 11:14:22 -0700
Subject: [PATCH] Bug 19270: Rancor - add ability to search batches by
arbitrary marc fields
To test:
1 - Open advanced cataloging editor
2 - In settings->import batches enable some batches for searching
3 - Click 'Advanced' in the search box
4 - Check an import batch, note a 'MARC field' searchbox appears
5 - Enter some test searches (use '*' as wildcard - add it to both ends
of value unless you want exact search)
6 - Note results appear as expected
---
Koha/MetaSearcher.pm | 25 ++++++++++++++++++++--
koha-tmpl/intranet-tmpl/prog/css/cateditor.css | 4 ++++
.../prog/en/includes/cateditor-ui.inc | 22 ++++++++++++++-----
.../prog/en/modules/cataloguing/editor.tt | 5 +++++
4 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/Koha/MetaSearcher.pm b/Koha/MetaSearcher.pm
index bff7ce3..21674cc 100644
--- a/Koha/MetaSearcher.pm
+++ b/Koha/MetaSearcher.pm
@@ -219,7 +219,9 @@ sub _pqf_query_from_terms {
my $query;
while ( my ( $index, $value ) = each %$terms ) {
- $value =~ s/"/\\"/;
+ next unless ( $_pqf_mapping->{$index} );
+
+ $value =~ s/"/\\"/g;
my $term = '@attr ' . $_pqf_mapping->{$index} . ' "' . $value . '"';
@@ -237,7 +239,7 @@ sub _db_query_get_match_conditions {
my ( $index, $value ) = @_;
if ( $value =~ /\*/ ) {
- $value =~ s/\*/%/;
+ $value =~ s/\*/%/g;
return { -like => $value };
} elsif ( $index eq 'isbn' ) {
return C4::Koha::GetNormalizedISBN($value) || $value;
@@ -269,6 +271,25 @@ sub _batch_db_query_from_terms {
# These are implicitly joined with OR because the arrayref doesn't start with -and
push @db_terms, \@term;
+ } elsif ( $index =~ /^marc-(\w{3})(\w)?$/ ) {
+ my $column;
+
+ # Yes, this is MySQL-specific and ugly. There seems to be no other way to ask
+ # SQL::Abstract to compare a function value.
+ if ( defined $2 ) {
+ $column = q{ExtractValue(marcxml, '//datafield[@tag="} . $1 . q{"]/subfield[@code="} . $2 . q{"]')};
+ } else {
+ $column = q{ExtractValue(marcxml, '//controlfield[@tag="} . $1 . q{"]')};
+ }
+
+ my $op = '=';
+
+ if ( $value =~ /\*/ ) {
+ $value =~ s/\*/%/g;
+ $op = 'LIKE';
+ }
+
+ push @db_terms, \[ "$column $op ?", $value ];
} elsif ( $_batch_db_mapping->{$index} ) {
push @db_terms, $_batch_db_mapping->{$index} => [ -and => _db_query_get_match_conditions( $index, $value ) ];
} else {
diff --git a/koha-tmpl/intranet-tmpl/prog/css/cateditor.css b/koha-tmpl/intranet-tmpl/prog/css/cateditor.css
index dd8b91c..afd5a1c 100644
--- a/koha-tmpl/intranet-tmpl/prog/css/cateditor.css
+++ b/koha-tmpl/intranet-tmpl/prog/css/cateditor.css
@@ -311,6 +311,10 @@ body {
width: 14em;
}
+#advanced-search-fields .marc-subfield-input {
+ width: 4em;
+}
+
.fa.fa-spinner {
display: inline-block;
height: 16px;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc
index 9c4aacd..5a7643f 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc
+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/cateditor-ui.inc
@@ -477,11 +477,19 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr
var terms = {};
$('#advanced-search-ui .search-box').each( function() {
- if ( !this.value ) return;
+ if ( !this.value || !$(this).data('qualifier') ) return;
terms[ $(this).data('qualifier') ] = this.value;
} );
+ var marc_subfield = $('#advanced-search-by-marc-subfield').val();
+ var marc_term = $('#advanced-search-by-marc').val();
+
+ // This mess (also used as a pattern="" in the form) allows 00X or XXXx).
+ if ( /^(00[0-9A-Za-z]|([1-9A-Za-z][0-9A-Za-z]{2}|0[1-9A-Za-z][0-9A-Za-z])[0-9A-Za-z])$/.test(marc_subfield) && marc_term ) {
+ terms[ 'marc-' + marc_subfield ] = marc_term;
+ }
+
if ( $.isEmptyObject(terms) ) return;
if ( Search.Run( z3950Servers, terms ) ) {
@@ -709,11 +717,16 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr
// Macros loaded on first show of modal
break;
case 'selected_search_targets':
+ var batch_selected_for_search = false;
$.each( z3950Servers, function( server_id, server ) {
var saved_val = Preferences.user.selected_search_targets[server_id];
if ( saved_val != null ) server.checked = saved_val;
+
+ if ( server.checked && /^batch:/.test(server_id) ) batch_selected_for_search = true;
} );
+
+ $('#arbitrary-marc-search').toggle( batch_selected_for_search );
break;
case 'selected_save_targets':
$.each( state.saveTargets, function( target_id, target ) {
@@ -729,7 +742,7 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr
function _addHandler( sel, event, handler ) {
$( sel ).on( event, function (e) {
e.preventDefault();
- handler( e, Preferences.user[pref] );
+ handler.call( this, e, Preferences.user[pref] );
Preferences.Save( [% USER_INFO.borrowernumber %] );
showPreference(pref);
} );
@@ -771,17 +784,16 @@ require( [ 'koha-backend', 'search', 'macros', 'marc-editor', 'marc-record', 'pr
} );
break;
case 'selected_save_targets':
- $( document ).on( 'change', 'input.save-toggle-target', function() {
+ _addLiveHandler( 'input.save-toggle-target', 'change', function() {
var target_id = $( this ).data('target-id');
Preferences.user.selected_save_targets[target_id] = this.checked;
Preferences.Save( [% USER_INFO.borrowernumber %] );
} );
break;
case 'selected_search_targets':
- $( document ).on( 'change', 'input.search-toggle-server', function() {
+ _addLiveHandler( 'input.search-toggle-server', 'change', function() {
var server_id = $( this ).closest('li').data('server-id');
Preferences.user.selected_search_targets[server_id] = this.checked;
- Preferences.Save( [% USER_INFO.borrowernumber %] );
} );
break;
}
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt
index a324842..bc802c0 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/editor.tt
@@ -176,6 +176,11 @@
<label for="advanced-search-by-publication-date">Publication date:</label>
<input class="search-box" data-qualifier="date" id="advanced-search-by-publication-date" />
</li>
+ <li id="arbitrary-marc-search" style="display-none">
+ <label for="advanced-search-by-marc">MARC field/subfield (XXXx):</label>
+ <input class="marc-subfield-input" id="advanced-search-by-marc-subfield" pattern="00[0-9A-Za-z]|([1-9A-Za-z][0-9A-Za-z]{2}|0[1-9A-Za-z][0-9A-Za-z])[0-9A-Za-z]" />
+ <input class="search-box" id="advanced-search-by-marc" />
+ </li>
</ul>
</div>
</div>
--
2.7.4