View | Details | Raw Unified | Return to bug 8209
Collapse All | Expand All

(-)a/C4/AuthoritiesMarc.pm (+3 lines)
Lines 263-268 sub SearchAuthorities { Link Here
263
                else {
263
                else {
264
                    $attr .= " \@attr 5=1 \@attr 4=6 "
264
                    $attr .= " \@attr 5=1 \@attr 4=6 "
265
                      ;    ## Word list, right truncated, anywhere
265
                      ;    ## Word list, right truncated, anywhere
266
                      if ($sortby eq 'Relevance') {
267
                          $attr .= "\@attr 2=102 ";
268
                      }
266
                }
269
                }
267
                @$value[$i] =~ s/"/\\"/g; # Escape the double-quotes in the search value
270
                @$value[$i] =~ s/"/\\"/g; # Escape the double-quotes in the search value
268
                $attr =$attr."\"".@$value[$i]."\"";
271
                $attr =$attr."\"".@$value[$i]."\"";
(-)a/Koha/SuggestionEngine.pm (+196 lines)
Line 0 Link Here
1
package Koha::SuggestionEngine;
2
3
# Copyright 2012 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
Koha::SuggestionEngine - Dispatcher class for suggestion engines
23
24
=head1 SYNOPSIS
25
26
  use Koha::SuggestionEngine;
27
  my $suggestor = Koha::SuggestionEngine->new(%params);
28
  $suggestor->get_suggestions($search)
29
30
=head1 DESCRIPTION
31
32
Dispatcher class for retrieving suggestions. SuggestionEngines must
33
extend Koha::SuggestionEngine::Base, be in the Koha::SuggestionEngine::Plugin
34
namespace, and provide the following methods:
35
36
B<get_suggestions ($search)> - get suggestions from the plugin for the
37
specified search.
38
39
These methods may be overriden:
40
41
B<initialize (%params)> - initialize the plugin
42
43
B<destroy ()> - destroy the plugin
44
45
These methods should not be overridden unless you are very sure of what
46
you are doing:
47
48
B<new ()> - create a new plugin object
49
50
=head1 FUNCTIONS
51
52
=cut
53
54
use strict;
55
use warnings;
56
use Module::Load::Conditional qw(can_load);
57
use Module::Pluggable::Object;
58
59
use base qw(Class::Accessor);
60
61
__PACKAGE__->mk_accessors(qw( schema plugins options record ));
62
63
=head2 new
64
65
    my $suggestor = Koha::SuggestionEngine->new(%params);
66
67
Create a new suggestor class. Available parameters are:
68
69
=over 8
70
71
=item B<plugins>
72
73
What plugin(s) to use. This must be an arrayref to a list of plugins. Plugins
74
can be specified either with a complete class path, or, if they are in the
75
Koha::SuggestionEngine::Plugin namespace, as only the plugin name, and
76
"Koha::SuggestionEngine::Plugin" will be prepended to it before the plugin
77
is loaded.
78
79
=back
80
81
=cut
82
83
sub new {
84
    my $class = shift;
85
    my $param = shift;
86
87
    my $options = $param->{options} || '';
88
    my @plugins = ();
89
90
    foreach my $plugin ( $param->{plugins} ) {
91
        next unless $plugin;
92
        my $plugin_module =
93
            $plugin =~ m/:/
94
          ? $plugin
95
          : "Koha::SuggestionEngine::Plugin::${plugin}";
96
        if ( can_load( modules => { $plugin_module => undef } ) ) {
97
            my $object = $plugin_module->new();
98
            $plugin_module->initialize($param);
99
            push @plugins, $object;
100
        }
101
    }
102
103
    my $self = $class->SUPER::new(
104
        {
105
            plugins => \@plugins,
106
            options => $options
107
        }
108
    );
109
    bless $self, $class;
110
    return $self;
111
}
112
113
=head2 get_suggestions
114
115
    my $suggestions = $suggester->get_suggestions(\%params)
116
117
Get a list of suggestions based on the search passed in. Available parameters
118
are:
119
120
=over 8
121
122
=item B<search>
123
124
Required. The search for which suggestions are desired.
125
126
=item B<count>
127
128
Optional. The number of suggestions to retrieve. Defaults to 10.
129
130
=back
131
132
=cut
133
134
sub get_suggestions {
135
    my $self  = shift;
136
    my $param = shift;
137
138
    return unless $param->{'search'};
139
140
    my $number = $param->{'count'} || 10;
141
142
    my %suggestions;
143
144
    foreach my $pluginobj ( @{ $self->plugins } ) {
145
        next unless $pluginobj;
146
        my $pluginres = $pluginobj->get_suggestions($param);
147
        foreach my $suggestion (@$pluginres) {
148
            $suggestions{ $suggestion->{'search'} }->{'relevance'} +=
149
              $suggestion->{'relevance'};
150
            $suggestions{ $suggestion->{'search'} }->{'label'} |=
151
              $suggestion->{'label'};
152
        }
153
    }
154
155
    my @results = ();
156
    for (
157
        sort {
158
            $suggestions{$b}->{'relevance'} <=> $suggestions{$a}->{'relevance'}
159
        } keys %suggestions
160
      )
161
    {
162
        last if ( $#results == $number - 1 );
163
        push @results,
164
          {
165
            'search'  => $_,
166
            relevance => $suggestions{$_}->{'relevance'},
167
            label     => $suggestions{$_}->{'label'}
168
          };
169
    }
170
171
    return \@results;
172
}
173
174
sub DESTROY {
175
    my $self = shift;
176
177
    foreach my $pluginobj ( @{ $self->plugins } ) {
178
        $pluginobj->destroy();
179
    }
180
}
181
182
=head2 AvailablePlugins
183
184
    my @available_plugins = Koha::SuggestionEngine::AvailablePlugins();
185
186
Get a list of available plugins.
187
188
=cut
189
190
sub AvailablePlugins {
191
    my $path = 'Koha::SuggestionEngine::Plugin';
192
    my $finder = Module::Pluggable::Object->new( search_path => $path );
193
    return $finder->plugins;
194
}
195
196
1;
(-)a/Koha/SuggestionEngine/Base.pm (+128 lines)
Line 0 Link Here
1
package Koha::SuggestionEngine::Base;
2
3
# Copyright 2012 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
Koha::SuggestionEngine::Base - Base class for SuggestionEngine plugins
23
24
=head1 SYNOPSIS
25
26
  use base qw(Koha::SuggestionEngine::Base);
27
28
=head1 DESCRIPTION
29
30
Base class for suggestion engine plugins. SuggestionEngines must
31
provide the following methods:
32
33
B<get_suggestions (\%param)> - get suggestions for the search described
34
in $param->{'search'}, and return them in a hashref with the suggestions
35
as keys and relevance as values.
36
37
The following variables must be defined in each filter:
38
  our $NAME ='Filter';
39
  our $VERSION = '1.0';
40
41
These methods may be overriden:
42
43
B<initialize (%params)> - initialize the plugin
44
45
B<destroy ()> - destroy the plugin
46
47
These methods should not be overridden unless you are very sure of what
48
you are doing:
49
50
B<new ()> - create a new plugin object
51
52
=head1 FUNCTIONS
53
54
=cut
55
56
use strict;
57
use warnings;
58
59
use base qw(Class::Accessor);
60
61
__PACKAGE__->mk_ro_accessors(qw( name version ));
62
__PACKAGE__->mk_accessors(qw( params ));
63
our $NAME    = 'Base';
64
our $VERSION = '1.0';
65
66
=head2 new
67
68
    my $plugin = Koha::SuggestionEngine::Base->new;
69
70
Create a new filter;
71
72
=cut
73
74
sub new {
75
    my $class = shift;
76
77
    my $self = $class->SUPER::new( {} );    #name => $class->NAME,
78
                                            #version => $class->VERSION });
79
80
    bless $self, $class;
81
    return $self;
82
}
83
84
=head2 initialize
85
86
    $plugin->initalize(%params);
87
88
Initialize a filter using the specified parameters.
89
90
=cut
91
92
sub initialize {
93
    my $self   = shift;
94
    my $params = shift;
95
96
    #$self->params = $params;
97
98
    return $self;
99
}
100
101
=head2 destroy
102
103
    $plugin->destroy();
104
105
Destroy the filter.
106
107
=cut
108
109
sub destroy {
110
    my $self = shift;
111
    return;
112
}
113
114
=head2 get_suggestions
115
116
    my $suggestions = $plugin->get_suggestions(\%param);
117
118
Return suggestions for the specified search.
119
120
=cut
121
122
sub get_suggestions {
123
    my $self  = shift;
124
    my $param = shift;
125
    return;
126
}
127
128
1;
(-)a/Koha/SuggestionEngine/Plugin/AuthorityFile.pm (+87 lines)
Line 0 Link Here
1
package Koha::SuggestionEngine::Plugin::AuthorityFile;
2
3
# Copyright 2012 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
Koha::SuggestionEngine::Plugin::AuthorityFile - get suggestions from the authority file
23
24
=head1 SYNOPSIS
25
26
27
=head1 DESCRIPTION
28
29
Plugin to get suggestions from Koha's authority file
30
31
=cut
32
33
use strict;
34
use warnings;
35
use Carp;
36
37
use base qw(Koha::SuggestionEngine::Base);
38
our $NAME    = 'EmbedItems';
39
our $VERSION = '1.0';
40
41
=head2 get_suggestions
42
43
    my $suggestions = $plugin->get_suggestions(\%param);
44
45
Return suggestions for the specified search by searching for the
46
search terms in the authority file and returning the results.
47
48
=cut
49
50
sub get_suggestions {
51
    my $self  = shift;
52
    my $param = shift;
53
54
    my $search = $param->{'search'};
55
56
    # Remove any CCL. This does not handle CQL or PQF, which is unfortunate,
57
    # but what can you do? At some point the search will have to be passed
58
    # not as a string but as some sort of data structure, at which point it
59
    # will be possible to support multiple search syntaxes.
60
    $search =~ s/ccl=//;
61
    $search =~ s/\w*[:=](\w*)/$1/g;
62
63
    my @marclist  = ['mainentry'];
64
    my @and_or    = ['and'];
65
    my @excluding = [];
66
    my @operator  = ['any'];
67
    my @value     = ["$search"];
68
69
    # FIXME: calling into C4
70
    require C4::AuthoritiesMarc;
71
    my ( $searchresults, $count ) = C4::AuthoritiesMarc::SearchAuthorities(
72
        \@marclist,  \@and_or, \@excluding,       \@operator,
73
        @value,      0,        $param->{'count'}, '',
74
        'Relevance', 0
75
    );
76
77
    my @results;
78
    foreach my $auth (@$searchresults) {
79
        push @results,
80
          {
81
            'search'  => "an=$auth->{'authid'}",
82
            relevance => $count--,
83
            label     => $auth->{summary}->{authorized}->[0]
84
          };
85
    }
86
    return \@results;
87
}
(-)a/Koha/SuggestionEngine/Plugin/Null.pm (+60 lines)
Line 0 Link Here
1
package Koha::SuggestionEngine::Plugin::Null;
2
3
# Copyright 2012 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
Koha::SuggestionEngine::Plugin::Null - an example plugin that does nothing but allow us to run tests
23
24
=head1 SYNOPSIS
25
26
27
=head1 DESCRIPTION
28
29
Plugin to allow us to run unit tests and regression tests against the
30
SuggestionEngine.
31
32
=cut
33
34
use strict;
35
use warnings;
36
use Carp;
37
38
use base qw(Koha::SuggestionEngine::Base);
39
our $NAME    = 'Null';
40
our $VERSION = '1.0';
41
42
=head2 get_suggestions
43
44
    my $suggestions = $suggestor->get_suggestions( {search => 'books');
45
46
Return a boring suggestion.
47
48
=cut
49
50
sub get_suggestions {
51
    my $self  = shift;
52
    my $param = shift;
53
54
    my @result = ();
55
56
    push @result, { search => 'book', label => 'Book!', relevance => 1 }
57
      if ( $param->{'search'} eq 'books' );
58
59
    return \@result;
60
}
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 375-377 INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ( Link Here
375
INSERT INTO systempreferences (variable,value,explanation,type) VALUES('EnableBorrowerFiles','0','If enabled, allows librarians to upload and attach arbitrary files to a borrower record.','YesNo');
375
INSERT INTO systempreferences (variable,value,explanation,type) VALUES('EnableBorrowerFiles','0','If enabled, allows librarians to upload and attach arbitrary files to a borrower record.','YesNo');
376
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('UpdateTotalIssuesOnCirc','0','Whether to update the totalissues field in the biblio on each circ.',NULL,'YesNo');
376
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('UpdateTotalIssuesOnCirc','0','Whether to update the totalissues field in the biblio on each circ.',NULL,'YesNo');
377
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('IntranetSlipPrinterJS','','Use this JavaScript for printing slips. Define at least function printThenClose(). For use e.g. with Firefox PlugIn jsPrintSetup, see http://jsprintsetup.mozdev.org/','','Free');
377
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('IntranetSlipPrinterJS','','Use this JavaScript for printing slips. Define at least function printThenClose(). For use e.g. with Firefox PlugIn jsPrintSetup, see http://jsprintsetup.mozdev.org/','','Free');
378
INSERT INTO systempreferences (variable,value,explanation,type) VALUES('DidYouMeanFromAuthorities','0','Suggest searches based on authority file.','YesNo');
(-)a/installer/data/mysql/updatedatabase.pl (+8 lines)
Lines 5610-5615 if (C4::Context->preference("Version") < TransformToNum($DBversion)) { Link Here
5610
    SetVersion($DBversion);
5610
    SetVersion($DBversion);
5611
}
5611
}
5612
5612
5613
5614
$DBversion ="3.09.00.XXX";
5615
if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
5616
    $dbh->do("INSERT INTO systempreferences (variable,value,explanation,type) VALUES('DidYouMeanFromAuthorities','0','Suggest searches based on authority file.','YesNo');");
5617
    print "Upgrade to $DBversion done (Add system preference DidYouMeanFromAuthorities))\n";
5618
    SetVersion($DBversion);
5619
}
5620
5613
=head1 FUNCTIONS
5621
=head1 FUNCTIONS
5614
5622
5615
=head2 TableExists($table)
5623
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref (+7 lines)
Lines 76-81 Searching: Link Here
76
                  yes: Using
76
                  yes: Using
77
                  no: "Not using"
77
                  no: "Not using"
78
            - 'ICU Zebra indexing. Please note: This setting will not affect Zebra indexing, it should only be used to tell Koha that you have activated ICU indexing if you have actually done so, since there is no way for Koha to figure this out on its own.'
78
            - 'ICU Zebra indexing. Please note: This setting will not affect Zebra indexing, it should only be used to tell Koha that you have activated ICU indexing if you have actually done so, since there is no way for Koha to figure this out on its own.'
79
        -
80
            - pref: DidYouMeanFromAuthorities
81
              default: 0
82
              choices:
83
                  yes: Suggest
84
                  no: "Don't suggest"
85
            - alternate searches based on data in the authority file.
79
    Search Form:
86
    Search Form:
80
        -
87
        -
81
            - Show tabs in OPAC and staff-side advanced search for limiting searches on the
88
            - Show tabs in OPAC and staff-side advanced search for limiting searches on the
(-)a/koha-tmpl/opac-tmpl/prog/en/css/opac.css (+19 lines)
Lines 2609-2614 ul.ui-tabs-nav li { Link Here
2609
    margin-left: 0.5em;
2609
    margin-left: 0.5em;
2610
}
2610
}
2611
2611
2612
#didyoumean {
2613
    background-color: #EEE;
2614
    border: 1px solid #E8E8E8;
2615
    margin-bottom: 4px;
2616
    text-align: center;
2617
    padding: 0.5em 0;
2618
}
2619
2620
.suggestionlabel {
2621
    font-weight: bold;
2622
}
2623
2624
.searchsuggestion {
2625
    border: 2px outset #E8E8E8;
2626
    padding: 0.2em;
2627
    white-space: nowrap;
2628
    display: inline-block;
2629
}
2630
2612
/* jQuery UI Datepicker */
2631
/* jQuery UI Datepicker */
2613
.ui-datepicker-trigger {
2632
.ui-datepicker-trigger {
2614
    vertical-align: middle;
2633
    vertical-align: middle;
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt (-10 / +5 lines)
Lines 252-257 $(document).ready(function(){ Link Here
252
    [% IF OpenLibraryCovers %]KOHA.OpenLibrary.GetCoverFromIsbn();[% END %]
252
    [% IF OpenLibraryCovers %]KOHA.OpenLibrary.GetCoverFromIsbn();[% END %]
253
    [% IF OPACLocalCoverImages %]KOHA.LocalCover.GetCoverFromBibnumber(false);[% END %]
253
    [% IF OPACLocalCoverImages %]KOHA.LocalCover.GetCoverFromBibnumber(false);[% END %]
254
    [% IF ( GoogleJackets ) %]KOHA.Google.GetCoverFromIsbn();[% END %]
254
    [% IF ( GoogleJackets ) %]KOHA.Google.GetCoverFromIsbn();[% END %]
255
256
    $('#didyoumean').load('/cgi-bin/koha/svc/suggestion?render=stub&q=[% querystring | uri %]');
255
});
257
});
256
258
257
//]]>
259
//]]>
Lines 267-282 $(document).ready(function(){ Link Here
267
    <div id="yui-main">
269
    <div id="yui-main">
268
    <div class="yui-b">
270
    <div class="yui-b">
269
    <div id="userresults" class="container">
271
    <div id="userresults" class="container">
270
  [% IF ( koha_spsuggest ) %]
272
    [% IF ( DidYouMeanFromAuthorities ) %]
271
    Did you mean:
273
        <div id='didyoumean'>Not what you expected? Check for <a href='/cgi-bin/koha/svc/suggestion?render=standalone&q=[% querystring | uri %]'>suggestions</a></div>
272
    <ul style="list-style: none;">
274
    [% END %]
273
        [% FOREACH SPELL_SUGGES IN SPELL_SUGGEST %]
274
        <li>
275
            <a href="/cgi-bin/koha/opac-search.pl?q=[% SPELL_SUGGES.spsuggestion %]">[% SPELL_SUGGES.spsuggestion %]</a>
276
        </li>
277
        [% END %]
278
    </ul>
279
[% END %]
280
275
281
[% IF ( query_error ) %]
276
[% IF ( query_error ) %]
282
<div class="dialog alert">
277
<div class="dialog alert">
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/svc/suggestion.tt (+36 lines)
Line 0 Link Here
1
[% IF (render=='standalone') %]
2
[% INCLUDE 'doc-head-open.inc' %]Search suggestions</title>
3
    [% INCLUDE 'doc-head-close.inc' %]
4
</head>
5
<body id="opac-suggestion">
6
    [% IF ( OpacNav ) %]<div id="doc3" class="yui-t1">[% ELSE %]<div id="doc3" class="yui-t7">[% END %]
7
        <div id="bd">
8
            [% INCLUDE 'masthead.inc' %]
9
            <div id="yui-main">
10
            <div class="yui-b">
11
            <div class="yui-ge">
12
            <div class="container">
13
            <h1 class="title">Suggestions</h1>
14
[% END %]
15
[% IF suggestions && suggestions.size %]
16
    <div>
17
    <span class='suggestionlabel'>Did you mean:</span>
18
    [% FOREACH suggestion IN suggestions %]
19
        <span class='searchsuggestion'><a href='/cgi-bin/koha/opac-search.pl?q=[% suggestion.search | uri %]'>[% suggestion.label %]</a></span>
20
    [% END %]
21
    </div>
22
[% ELSE %]
23
    <span class='nosuggestions'>Sorry, no suggestions.</span>
24
[% END %]
25
[% IF (render=='standalone') %]
26
    </div>
27
    </div>
28
    </div>
29
    [% IF ( OpacNav ) %]
30
        <div class="yui-b"><div id="leftmenus" class="container">
31
        [% INCLUDE 'navigation.inc' %]
32
        </div></div>
33
    [% END %]
34
    </div>
35
    [% INCLUDE 'opac-bottom.inc' %]
36
[% END %]
(-)a/opac/opac-search.pl (+4 lines)
Lines 369-374 if ($indexes[0] && !$indexes[1]) { Link Here
369
my @operands;
369
my @operands;
370
@operands = split("\0",$params->{'q'}) if $params->{'q'};
370
@operands = split("\0",$params->{'q'}) if $params->{'q'};
371
371
372
$template->{VARS}->{querystring} = join(' ', @operands);
373
372
# if a simple search, display the value in the search box
374
# if a simple search, display the value in the search box
373
if ($operands[0] && !$operands[1]) {
375
if ($operands[0] && !$operands[1]) {
374
    $template->param(ms_value => $operands[0]);
376
    $template->param(ms_value => $operands[0]);
Lines 816-820 if (C4::Context->preference('GoogleIndicTransliteration')) { Link Here
816
        $template->param('GoogleIndicTransliteration' => 1);
818
        $template->param('GoogleIndicTransliteration' => 1);
817
}
819
}
818
820
821
$template->{VARS}->{DidYouMeanFromAuthorities} = C4::Context->preference('DidYouMeanFromAuthorities');
822
819
    $template->param( borrowernumber    => $borrowernumber);
823
    $template->param( borrowernumber    => $borrowernumber);
820
output_with_http_headers $cgi, $cookie, $template->output, $content_type;
824
output_with_http_headers $cgi, $cookie, $template->output, $content_type;
(-)a/opac/svc/suggestion (+101 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 C & P Bibliography Services
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
opac-suggestion.pl : script to render suggestions for the OPAC
23
24
=head1 SYNOPSIS
25
26
=cut
27
28
=head1 DESCRIPTION
29
30
This script produces suggestions for the OPAC given a search string.
31
32
It takes the following parameters:
33
34
=over 8
35
36
=item I<q>
37
38
Required. Query string.
39
40
=item I<render>
41
42
If set to 'stub' render a stub HTML page suitable for inclusion into a
43
div via AJAX. If set to 'standalone', return a full page instead of the stub.
44
If not set, return JSON.
45
46
=item I<count>
47
48
Number of suggestions to display. Defaults to 4 in stub mode, 20 otherwise.
49
50
=back
51
52
=cut
53
54
use strict;
55
use warnings;
56
57
use C4::Auth;
58
use C4::Context;
59
use C4::Output;
60
use CGI;
61
use JSON;
62
use Koha::SuggestionEngine;
63
64
my $query = new CGI;
65
66
my $dbh = C4::Context->dbh;
67
68
my $search = $query->param('q')      || '';
69
my $render = $query->param('render') || '';
70
my $count  = $query->param('count')  || ( $render eq 'stub' ? 4 : 20 );
71
72
# open template
73
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
74
    {
75
        template_name   => "svc/suggestion.tt",
76
        query           => $query,
77
        type            => "opac",
78
        authnotrequired => ( C4::Context->preference("OpacPublic") ? 1 : 0 ),
79
        debug           => 1,
80
    }
81
);
82
83
unless ( C4::Context->preference('DidYouMeanFromAuthorities') ) {
84
    print $query->header;
85
    exit;
86
}
87
88
my $suggestor = Koha::SuggestionEngine->new( { plugins => ('AuthorityFile') } );
89
90
my $suggestions =
91
  $suggestor->get_suggestions( { search => $search, count => $count } );
92
93
if ($render) {
94
    $template->{VARS}->{render} = $render;
95
    $template->{VARS}->{suggestions} = $suggestions if $suggestions;
96
    output_html_with_http_headers $query, $cookie, $template->output;
97
}
98
else {
99
    print $query->header;
100
    print to_json($suggestions);
101
}
(-)a/t/SuggestionEngine.t (+46 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use strict;
4
use warnings;
5
use File::Spec;
6
7
use Test::More;
8
9
BEGIN {
10
        use_ok('Koha::SuggestionEngine');
11
}
12
13
my $plugindir = File::Spec->rel2abs('Koha/SuggestionEngine/Plugin');
14
15
opendir(my $dh, $plugindir);
16
my @installed_plugins = map { ( /\.pm$/ && -f "$plugindir/$_" && s/\.pm$// ) ? "Koha::SuggestionEngine::Plugin::$_" : () } readdir($dh);
17
my @available_plugins = Koha::SuggestionEngine::AvailablePlugins();
18
19
foreach my $plugin (@installed_plugins) {
20
    ok(grep($plugin, @available_plugins), "Found plugin $plugin");
21
}
22
23
my $suggestor = Koha::SuggestionEngine->new( { plugins => ( 'ABCD::EFGH::IJKL' ) } );
24
25
is(ref($suggestor), 'Koha::SuggestionEngine', 'Created suggestion engine with invalid plugin');
26
is(scalar @{ $suggestor->get_suggestions({ 'search' => 'books' }) }, 0 , 'Request suggestions with empty suggestor');
27
28
$suggestor = Koha::SuggestionEngine->new( { plugins => ( 'Null' ) } );
29
is(ref($suggestor->plugins->[0]), 'Koha::SuggestionEngine::Plugin::Null', 'Created record suggestor with implicitly scoped Null filter');
30
31
$suggestor = Koha::SuggestionEngine->new( { plugins => ( 'Koha::SuggestionEngine::Plugin::Null' ) } );
32
is(ref($suggestor->plugins->[0]), 'Koha::SuggestionEngine::Plugin::Null', 'Created record suggestor with explicitly scoped Null filter');
33
34
my $suggestions = $suggestor->get_suggestions({ 'search' => 'books' });
35
36
is_deeply($suggestions->[0], { 'search' => 'book', label => 'Book!', relevance => 1 }, "Good suggestion");
37
38
$suggestions = $suggestor->get_suggestions({ 'search' => 'silliness' });
39
40
eval {
41
    $suggestor = Koha::SuggestionEngine->new( { plugins => ( 'Koha::SuggestionEngine::Plugin::Null' ) } );
42
    undef $suggestor;
43
};
44
ok(!$@, 'Destroyed suggestor successfully');
45
46
done_testing();
(-)a/t/SuggestionEngine_AuthorityFile.t (-1 / +43 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
#
3
# This Koha test module uses Test::MockModule to get around the need for known
4
# contents in the authority file by returning a single known authority record
5
# for every call to SearchAuthorities
6
7
use strict;
8
use warnings;
9
use File::Spec;
10
use MARC::Record;
11
12
use Test::More;
13
use Test::MockModule;
14
15
BEGIN {
16
        use_ok('Koha::SuggestionEngine');
17
}
18
19
my $module = new Test::MockModule('C4::AuthoritiesMarc');
20
$module->mock('SearchAuthorities', sub {
21
        return [ { 'authid' => '1234',
22
                    'reported_tag' => undef,
23
                    'even' => 0,
24
                    'summary' => {
25
                        'authorized' => [ 'Cooking' ],
26
                        'otherscript' => [],
27
                        'seefrom' => [ 'Cookery' ],
28
                        'notes' => [ 'Your quintessential poor heading selection' ],
29
                        'seealso' => []
30
                    },
31
                    'used' => 1,
32
                    'authtype' => 'Topical Term'
33
                } ], 1
34
});
35
36
my $suggestor = Koha::SuggestionEngine->new( { plugins => ( 'AuthorityFile' ) } );
37
is(ref($suggestor), 'Koha::SuggestionEngine', 'Created suggestion engine');
38
39
my $result = $suggestor->get_suggestions({search => 'Cookery'});
40
41
is_deeply($result, [ { 'search' => 'an=1234', 'relevance' => 1, 'label' => 'Cooking' } ], "Suggested correct alternative to 'Cookery'");
42
43
done_testing();

Return to bug 8209