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

(-)a/C4/Biblio.pm (-1 / +1 lines)
Lines 657-663 sub LinkBibHeadingsToAuthorities { Link Here
657
    }
657
    }
658
658
659
Check whether the specified heading-auth link is valid without reference
659
Check whether the specified heading-auth link is valid without reference
660
to Zebra/Solr. Ideally this code would be in C4::Heading, but that won't be
660
to Zebra. Ideally this code would be in C4::Heading, but that won't be
661
possible until we have de-cycled C4::AuthoritiesMarc, so this is the
661
possible until we have de-cycled C4::AuthoritiesMarc, so this is the
662
safest place.
662
safest place.
663
663
(-)a/C4/Installer/PerlDependencies.pm (-35 lines)
Lines 552-592 our $PERL_DEPS = { Link Here
552
        'required' => '1',
552
        'required' => '1',
553
        'min_ver'  => '0.03',
553
        'min_ver'  => '0.03',
554
    },
554
    },
555
    'Data::Paginator' => {
556
        'usage'    => 'Core',
557
        'required' => '0',
558
        'min_ver'  => '0.04',
559
    },
560
    'Data::Pagination' => {
561
        'usage'    => 'Core',
562
        'required' => '0',
563
        'min_ver'  => '0.44',
564
    },
565
    'JSON::Any' => {
566
        'usage'    => 'Core',
567
        'required' => '0',
568
        'min_ver'  => '1.28',
569
    },
570
    'MooseX::Storage' => {
571
        'usage'    => 'Core',
572
        'required' => '0',
573
        'min_ver'  => '0.30',
574
    },
575
    'MooseX::Types' => {
576
        'usage'    => 'Core',
577
        'required' => '0',
578
        'min_ver'  => '0.30',
579
    },
580
    'String::RewritePrefix' => {
581
        'usage'    => 'Core',
582
        'required' => '0',
583
        'min_ver'  => '0.006',
584
    },
585
    'Time::Progress' => {
586
        'usage'    => 'Core',
587
        'required' => '0',
588
        'min_ver'  => '1.7',
589
    },
590
    'DBD::Mock' => {
555
    'DBD::Mock' => {
591
        'usage'    => 'Core',
556
        'usage'    => 'Core',
592
        'required' => '1',
557
        'required' => '1',
(-)a/Koha/SearchEngine.pm (-46 lines)
Lines 1-46 Link Here
1
package Koha::SearchEngine;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
use C4::Context;
22
use Koha::SearchEngine::Config;
23
24
has 'name' => (
25
    is => 'ro',
26
    default => sub {
27
        C4::Context->preference('SearchEngine');
28
    }
29
);
30
31
has config => (
32
    is => 'rw',
33
    lazy => 1,
34
    default => sub {
35
        Koha::SearchEngine::Config->new;
36
    }
37
#    lazy => 1,
38
#    builder => '_build_config',
39
);
40
41
#sub _build_config {
42
#    my ( $self ) = @_;
43
#    Koha::SearchEngine::Config->new( $self->name );
44
#);
45
46
1;
(-)a/Koha/SearchEngine/Config.pm (-29 lines)
Lines 1-29 Link Here
1
package Koha::SearchEngine::Config;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
22
use Moose::Util qw( apply_all_roles );
23
24
sub BUILD {
25
    my $self = shift;
26
    my $syspref = C4::Context->preference("SearchEngine");
27
    apply_all_roles( $self, "Koha::SearchEngine::${syspref}::Config" );
28
};
29
1;
(-)a/Koha/SearchEngine/ConfigRole.pm (-24 lines)
Lines 1-24 Link Here
1
package Koha::SearchEngine::ConfigRole;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose::Role;
21
22
requires 'indexes', 'index', 'ressource_types';
23
24
1;
(-)a/Koha/SearchEngine/FacetsBuilder.pm (-29 lines)
Lines 1-29 Link Here
1
package Koha::SearchEngine::FacetsBuilder;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
22
use Moose::Util qw( apply_all_roles );
23
24
sub BUILD {
25
    my $self = shift;
26
    my $syspref = C4::Context->preference("SearchEngine");
27
    apply_all_roles( $self, "Koha::SearchEngine::${syspref}::FacetsBuilder" );
28
};
29
1;
(-)a/Koha/SearchEngine/FacetsBuilderRole.pm (-24 lines)
Lines 1-24 Link Here
1
package Koha::SearchEngine::FacetsBuilderRole;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose::Role;
21
22
requires 'build_facets';
23
24
1;
(-)a/Koha/SearchEngine/Index.pm (-29 lines)
Lines 1-29 Link Here
1
package Koha::SearchEngine::Index;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
22
use Moose::Util qw( apply_all_roles );
23
24
sub BUILD {
25
    my $self = shift;
26
    my $syspref = 'Solr';
27
    apply_all_roles( $self, "Koha::SearchEngine::${syspref}::Index" );
28
};
29
1;
(-)a/Koha/SearchEngine/IndexRole.pm (-24 lines)
Lines 1-24 Link Here
1
package Koha::SearchEngine::IndexRole;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose::Role;
21
22
requires 'index_record';
23
24
1;
(-)a/Koha/SearchEngine/QueryBuilder.pm (-29 lines)
Lines 1-29 Link Here
1
package Koha::SearchEngine::QueryBuilder;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
22
use Moose::Util qw( apply_all_roles );
23
24
sub BUILD {
25
    my $self = shift;
26
    my $syspref = C4::Context->preference("SearchEngine");
27
    apply_all_roles( $self, "Koha::SearchEngine::${syspref}::QueryBuilder" );
28
};
29
1;
(-)a/Koha/SearchEngine/QueryBuilderRole.pm (-24 lines)
Lines 1-24 Link Here
1
package Koha::SearchEngine::QueryBuilderRole;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose::Role;
21
22
requires 'build_query';
23
24
1;
(-)a/Koha/SearchEngine/Search.pm (-30 lines)
Lines 1-30 Link Here
1
package Koha::SearchEngine::Search;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
use C4::Context;
22
23
use Moose::Util qw( apply_all_roles );
24
25
sub BUILD {
26
    my $self = shift;
27
    my $syspref = C4::Context->preference("SearchEngine");
28
    apply_all_roles( $self, "Koha::SearchEngine::${syspref}::Search" );
29
};
30
1;
(-)a/Koha/SearchEngine/SearchRole.pm (-25 lines)
Lines 1-25 Link Here
1
package Koha::SearchEngine::SearchRole;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose::Role;
21
22
requires 'search';
23
requires 'dosmth';
24
25
1;
(-)a/Koha/SearchEngine/Solr.pm (-63 lines)
Lines 1-63 Link Here
1
package Koha::SearchEngine::Solr;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
use Koha::SearchEngine::Config;
22
23
extends 'Koha::SearchEngine', 'Data::SearchEngine::Solr';
24
25
has '+url' => (
26
    is => 'ro',
27
    isa => 'Str',
28
#    default => sub {
29
#        C4::Context->preference('SolrAPI');
30
#    },
31
    lazy => 1,
32
    builder => '_build_url',
33
    required => 1
34
);
35
36
sub _build_url {
37
    my ( $self ) = @_;
38
    $self->config->SolrAPI;
39
}
40
41
has '+options' => (
42
    is => 'ro',
43
    isa => 'HashRef',
44
    default => sub {
45
      {
46
        wt => 'json',
47
        fl => '*,score',
48
        fq => 'recordtype:biblio',
49
        facets => 'true'
50
      }
51
    }
52
53
);
54
55
has indexes => (
56
    is => 'ro',
57
    lazy => 1,
58
    default => sub {
59
#        my $dbh => ...;
60
    },
61
);
62
63
1;
(-)a/Koha/SearchEngine/Solr/Config.pm (-132 lines)
Lines 1-132 Link Here
1
package Koha::SearchEngine::Solr::Config;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Moose::Role;
22
use YAML;
23
24
with 'Koha::SearchEngine::ConfigRole';
25
26
has index_config => (
27
    is => 'rw',
28
    lazy => 1,
29
    builder => '_load_index_config_file',
30
);
31
32
has solr_config => (
33
    is => 'rw',
34
    lazy => 1,
35
    builder => '_load_solr_config_file',
36
);
37
38
has index_filename => (
39
    is => 'rw',
40
    lazy => 1,
41
    default => C4::Context->config("installdir") . qq{/etc/searchengine/solr/indexes.yaml},
42
);
43
has solr_filename => (
44
    is => 'rw',
45
    lazy => 1,
46
    default => C4::Context->config("installdir") . qq{/etc/searchengine/solr/config.yaml},
47
);
48
49
sub _load_index_config_file {
50
    my ( $self, $filename ) = @_;
51
    $self->index_filename( $filename ) if defined $filename;
52
    die "The config index file (" . $self->index_filename . ") for Solr is not exist" if not -e $self->index_filename;
53
54
    return YAML::LoadFile($self->index_filename);
55
}
56
57
sub _load_solr_config_file {
58
    my ( $self ) = @_;
59
    die "The solr config index file (" . $self->solr_filename . ") for Solr is not exist" if not -e $self->solr_filename;
60
61
    return YAML::LoadFile($self->solr_filename);
62
}
63
64
sub set_config_filename {
65
    my ( $self, $filename ) = @_;
66
    $self->index_config( $self->_load_index_config_file( $filename ) );
67
}
68
69
sub SolrAPI {
70
    my ( $self ) = @_;
71
    return $self->solr_config->{SolrAPI};
72
}
73
sub indexes { # FIXME Return index list if param not an hashref (string ressource_type)
74
    my ( $self, $indexes ) = @_;
75
    return $self->write( { indexes => $indexes } ) if defined $indexes;
76
    return $self->index_config->{indexes};
77
}
78
79
sub index {
80
    my ( $self, $code ) = @_;
81
    my @index = map { ( $_->{code} eq $code ) ? $_ : () } @{$self->index_config->{indexes}};
82
    return $index[0];
83
}
84
85
sub ressource_types {
86
    my ( $self  ) = @_;
87
    my $config = $self->index_config;
88
    return $config->{ressource_types};
89
}
90
91
sub sortable_indexes {
92
    my ( $self ) = @_;
93
    my @sortable_indexes = map { $_->{sortable} ? $_ : () } @{ $self->index_config->{indexes} };
94
    return \@sortable_indexes;
95
}
96
97
sub facetable_indexes {
98
    my ( $self ) = @_;
99
    my @facetable_indexes = map { $_->{facetable} ? $_ : () } @{ $self->index_config->{indexes} };
100
    return \@facetable_indexes;
101
}
102
103
sub reload {
104
    my ( $self ) = @_;
105
    $self->index_config( $self->_load_index_config_file );
106
}
107
sub write {
108
    my ( $self, $values ) = @_;
109
    my $r;
110
    while ( my ( $k, $v ) = each %$values ) {
111
        $r->{$k} = $v;
112
    }
113
114
    if ( not grep /^ressource_type$/, keys %$values ) {
115
        $r->{ressource_types} = $self->ressource_types;
116
    }
117
118
    if ( not grep /^indexes$/, keys %$values ) {
119
        $r->{indexes} = $self->indexes;
120
    }
121
122
    eval {
123
        YAML::DumpFile( $self->index_filename, $r );
124
    };
125
    if ( $@ ) {
126
        die "Failed to dump the index config into the specified file ($@)";
127
    }
128
129
    $self->reload;
130
}
131
132
1;
(-)a/Koha/SearchEngine/Solr/FacetsBuilder.pm (-58 lines)
Lines 1-58 Link Here
1
package Koha::SearchEngine::Solr::FacetsBuilder;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Moose::Role;
22
23
with 'Koha::SearchEngine::FacetsBuilderRole';
24
25
sub build_facets {
26
    my ( $self, $results, $facetable_indexes, $filters ) = @_;
27
    my @facets_loop;
28
    for my $index ( @$facetable_indexes ) {
29
        my $index_name = $index->{type} . '_' . $index->{code};
30
        my $facets = $results->facets->{'str_' . $index->{code}};
31
        if ( @$facets > 1 ) {
32
            my @values;
33
            $index =~ m/^([^_]*)_(.*)$/;
34
            for ( my $i = 0 ; $i < scalar(@$facets) ; $i++ ) {
35
                my $value = $facets->[$i++];
36
                my $count = $facets->[$i];
37
                utf8::encode($value);
38
                my $lib =$value;
39
                push @values, {
40
                    'lib'     => $lib,
41
                    'value'   => $value,
42
                    'count'   => $count,
43
                    'active'  => ( $filters->{$index_name} and scalar( grep /"?\Q$value\E"?/, @{ $filters->{$index_name} } ) ) ? 1 : 0,
44
                };
45
            }
46
47
            push @facets_loop, {
48
                'indexname' => $index_name,
49
                'label'     => $index->{label},
50
                'values'    => \@values,
51
                'size'      => scalar(@values),
52
            };
53
        }
54
    }
55
    return @facets_loop;
56
}
57
58
1;
(-)a/Koha/SearchEngine/Solr/Index.pm (-126 lines)
Lines 1-126 Link Here
1
package Koha::SearchEngine::Solr::Index;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
# Copyright 2012 C & P Bibliography Services
7
# Copyright 2012 PTFS-Europe Ltd.
8
#
9
# Koha is free software; you can redistribute it and/or modify it
10
# under the terms of the GNU General Public License as published by
11
# the Free Software Foundation; either version 3 of the License, or
12
# (at your option) any later version.
13
#
14
# Koha is distributed in the hope that it will be useful, but
15
# WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with Koha; if not, see <http://www.gnu.org/licenses>.
21
22
use Moose::Role;
23
with 'Koha::SearchEngine::IndexRole';
24
25
use Data::SearchEngine::Solr;
26
use Data::Dump qw(dump);
27
use List::MoreUtils qw(uniq);
28
29
use Koha::SearchEngine::Solr;
30
use C4::AuthoritiesMarc;
31
use C4::Biblio;
32
use Koha::RecordProcessor;
33
34
has searchengine => (
35
    is => 'rw',
36
    isa => 'Koha::SearchEngine::Solr',
37
    default => sub { Koha::SearchEngine::Solr->new },
38
    lazy => 1
39
);
40
41
sub optimize {
42
    my ( $self ) = @_;
43
    return $self->searchengine->_solr->optimize;
44
}
45
46
sub index_record {
47
    my ($self, $recordtype, $recordids) = @_;
48
49
    my $indexes = $self->searchengine->config->indexes;
50
    my @records;
51
52
    my $recordids_str = ref($recordids) eq 'ARRAY'
53
                    ? join " ", @$recordids
54
                    : $recordids;
55
    warn "IndexRecord called with $recordtype $recordids_str";
56
57
    for my $id ( @$recordids ) {
58
        my $record;
59
60
        $record = GetAuthority( $id )  if $recordtype eq "authority";
61
        $record = GetMarcBiblio( $id ) if $recordtype eq "biblio";
62
63
        if ($recordtype eq 'biblio' && C4::Context->preference('IncludeSeeFromInSearches')) {
64
            my $normalizer = Koha::RecordProcessor->new( { filters => 'EmbedSeeFromHeadings' } );
65
            $record = $normalizer->process($record);
66
        }
67
68
        next unless ( $record );
69
70
        my $index_values = {
71
            recordid => $id,
72
            recordtype => $recordtype,
73
        };
74
75
        warn "Indexing $recordtype $id";
76
77
        for my $index ( @$indexes ) {
78
            next if $index->{ressource_type} ne $recordtype;
79
            my @values;
80
            eval {
81
                my $mappings = $index->{mappings};
82
                for my $tag_subf_code ( sort @$mappings ) {
83
                    my ( $f, $sf ) = split /\$/, $tag_subf_code;
84
                    for my $field ( $record->field( $f ) ) {
85
                        if ( $field->is_control_field ) {
86
                            push @values, $field->data;
87
                        } else {
88
                            my @sfvals = $sf eq '*'
89
                                       ? map { $_->[1] } $field->subfields
90
                                       : map { $_      } $field->subfield( $sf );
91
92
                            for ( @sfvals ) {
93
                                $_ = NormalizeDate( $_ ) if $index->{type} eq 'date';
94
                                push @values, $_ if $_;
95
                            }
96
                        }
97
                    }
98
                }
99
                @values = uniq (@values); #Removes duplicates
100
101
                $index_values->{$index->{type}."_".$index->{code}} = \@values;
102
                if ( $index->{sortable} ){
103
                    $index_values->{"srt_" . $index->{type} . "_".$index->{code}} = $values[0];
104
                }
105
                # Add index str for facets if it's not exist
106
                if ( $index->{facetable} and @values > 0 and $index->{type} ne 'str' ) {
107
                    $index_values->{"str_" . $index->{code}} = $values[0];
108
                }
109
            };
110
            if ( $@ ) {
111
                chomp $@;
112
                warn  "Error during indexation : recordid $id, index $index->{code} ( $@ )";
113
            }
114
        }
115
116
        my $solrrecord = Data::SearchEngine::Item->new(
117
            id    => "${recordtype}_$id",
118
            score => 1,
119
            values => $index_values,
120
        );
121
        push @records, $solrrecord;
122
    }
123
    $self->searchengine->add( \@records );
124
}
125
126
1;
(-)a/Koha/SearchEngine/Solr/QueryBuilder.pm (-159 lines)
Lines 1-159 Link Here
1
package Koha::SearchEngine::Solr::QueryBuilder;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Moose::Role;
22
23
with 'Koha::SearchEngine::QueryBuilderRole';
24
25
sub build_advanced_query {
26
    my ($class, $indexes, $operands, $operators) = @_;
27
28
    my $q = '';
29
    my $i = 0;
30
    my $index_name;
31
32
    @$operands or return "*:*"; #push @$operands, "[* TO *]";
33
34
    # Foreach operands
35
    for my $kw (@$operands){
36
        $kw =~ s/(\w*\*)/\L$1\E/g; # Lower case on words with right truncation
37
        $kw =~ s/(\s*\w*\?+\w*\s*)/\L$1\E/g; # Lower case on words contain wildcard ?
38
        $kw =~ s/([^\\]):/$1\\:/g; # escape colons if not already escaped
39
        # First element
40
        if ($i == 0){
41
            if ( (my @x = eval {@$indexes} ) == 0 ){
42
                # There is no index, then query is in first operand
43
                $q = @$operands[0];
44
                last;
45
            }
46
47
            # Catch index name if it's not 'all_fields'
48
            if ( @$indexes[$i] ne 'all_fields' ) {
49
                $index_name = @$indexes[$i];
50
            }else{
51
                $index_name = '';
52
            }
53
54
            # Generate index:operand
55
            $q .= BuildTokenString($index_name, $kw);
56
            $i = $i + 1;
57
58
            next;
59
        }
60
        # And others
61
        $index_name = @$indexes[$i] if @$indexes[$i];
62
        my $operator = defined @$operators[$i-1] ? @$operators[$i-1] : 'AND';
63
        if ( uc ( $operator ) eq 'OR' ) {
64
            $q .= BuildTokenString($index_name, $kw, 'OR');
65
        } elsif ( uc ( $operator ) eq 'NOT' ) {
66
            $q .= BuildTokenString($index_name, $kw, 'NOT');
67
        } else {
68
            $q .= BuildTokenString($index_name, $kw, 'AND');
69
        }
70
        $i = $i + 1;
71
    }
72
73
    return $q;
74
75
}
76
77
sub BuildTokenString {
78
    my ($index, $string, $operator) = @_;
79
    my $r;
80
81
    if ($index ne 'all_fields' && $index ne ''){
82
        # Operand can contains an expression in brackets
83
        if (
84
            $string =~ / /
85
                and not ( $string =~ /^\(.*\)$/ )
86
                and not $string =~ /\[.*TO.*\]/ ) {
87
            my @dqs; #double-quoted string
88
            while ( $string =~ /"(?:[^"\\]++|\\.)*+"/g ) {
89
                push @dqs, $&;
90
                $string =~ s/\ *\Q$&\E\ *//; # Remove useless space before and after
91
            }
92
93
            my @words = defined $string ? split ' ', $string : undef;
94
            my $join = join qq{ AND } , map {
95
                my $value = $_;
96
                if ( $index =~ /^date_/ ) {
97
                    #$value = C4::Search::Engine::Solr::buildDateOperand( $value ); TODO
98
                }
99
                ( $value =~ /^"/ and $value ne '""'
100
                        and $index ne "emallfields"
101
                        and $index =~ /(txt_|ste_)/ )
102
                    ? qq{em$index:$value}
103
                    : qq{$index:$value};
104
            } (@dqs, @words);
105
            $r .= qq{($join)};
106
        } else {
107
            if ( $index =~ /^date_/ ) {
108
                #$string = C4::Search::Engine::Solr::buildDateOperand( $string ); TODO
109
            }
110
111
            $r = "$index:$string";
112
        }
113
    }else{
114
        $r = $string;
115
    }
116
117
    return " $operator $r" if $operator;
118
    return $r;
119
}
120
121
sub build_query {
122
    my ($class, $query) = @_;
123
124
    return "*:*" if not defined $query;
125
126
    # Particular *:* query
127
    if ($query  eq '*:*'){
128
        return $query;
129
    }
130
131
    $query =~ s/(\w*\*)/\L$1\E/g; # Lower case on words with right truncation
132
    $query =~ s/(\s*\w*\?+\w*\s*)/\L$1\E/g; # Lower case on words contain wildcard ?
133
134
    my @quotes; # Process colons in quotes
135
    while ( $query =~ /'(?:[^'\\]++|\\.)*+'/g ) {
136
        push @quotes, $&;
137
    }
138
139
    for ( @quotes ) {
140
        my $replacement = $_;
141
        $replacement =~ s/[^\\]\K:/\\:/g;
142
        $query =~ s/$_/$replacement/;
143
    }
144
145
    $query =~ s/ : / \\: /g; # escape colons if " : "
146
147
    my $new_query = $query;#C4::Search::Query::splitToken($query); TODO
148
149
    $new_query =~ s/all_fields://g;
150
151
    # Upper case for operators
152
    $new_query =~ s/ or / OR /g;
153
    $new_query =~ s/ and / AND /g;
154
    $new_query =~ s/ not / NOT /g;
155
156
    return $new_query;
157
}
158
159
1;
(-)a/Koha/SearchEngine/Solr/Search.pm (-128 lines)
Lines 1-128 Link Here
1
package Koha::SearchEngine::Solr::Search;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
# Copyright 2012 KohaAloha
7
#
8
# Koha is free software; you can redistribute it and/or modify it
9
# under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# Koha is distributed in the hope that it will be useful, but
14
# WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with Koha; if not, see <http://www.gnu.org/licenses>.
20
21
use Moose::Role;
22
with 'Koha::SearchEngine::SearchRole';
23
24
use Data::Dump qw(dump);
25
use XML::Simple;
26
27
use Data::SearchEngine::Solr;
28
use Data::Pagination;
29
use Data::SearchEngine::Query;
30
use Koha::SearchEngine::Solr;
31
32
has searchengine => (
33
    is => 'rw',
34
    isa => 'Koha::SearchEngine::Solr',
35
    default => sub { Koha::SearchEngine::Solr->new },
36
    lazy => 1
37
);
38
39
sub search {
40
    my ( $self, $q, $filters, $params ) = @_;
41
42
    $q         ||= '*:*';
43
    $filters   ||= {};
44
    my $page   = defined $params->{page}   ? $params->{page}   : 1;
45
    my $count  = defined $params->{count}  ? $params->{count}  : 999999999;
46
    my $sort   = defined $params->{sort}   ? $params->{sort}   : 'score desc';
47
    my $facets = defined $params->{facets} ? $params->{facets} : 0;
48
49
    # Construct fl from $params->{fl}
50
    # If "recordid" or "id" not exist, we push them
51
    my $fl = join ",",
52
        defined $params->{fl}
53
            ? (
54
                @{$params->{fl}},
55
                grep ( /^recordid$/, @{$params->{fl}} ) ? () : "recordid",
56
                grep ( /^id$/, @{$params->{fl}} ) ? () : "id"
57
              )
58
            : ( "recordid", "id" );
59
60
    my $recordtype;
61
    $recordtype = ref($filters->{recordtype}) eq 'ARRAY'
62
                    ? $filters->{recordtype}[0]
63
                    : $filters->{recordtype}
64
                if defined $filters && defined $filters->{recordtype};
65
66
    if ( $facets ) {
67
        $self->searchengine->options->{"facet"}          = 'true';
68
        $self->searchengine->options->{"facet.mincount"} = 1;
69
        $self->searchengine->options->{"facet.limit"}    = 10; # TODO create a new systempreference C4::Context->preference("numFacetsDisplay")
70
        my @facetable_indexes = map { 'str_' . $_->{code} } @{$self->searchengine->config->facetable_indexes};
71
        $self->searchengine->options->{"facet.field"}    = \@facetable_indexes;
72
    }
73
    $self->searchengine->options->{sort} = $sort;
74
    $self->searchengine->options->{fl} = $fl;
75
76
    # Construct filters
77
    $self->searchengine->options->{fq} = [
78
        map {
79
            my $idx = $_;
80
            ref($filters->{$idx}) eq 'ARRAY'
81
                ?
82
                    '('
83
                    . join( ' AND ',
84
                        map {
85
                            my $filter_str = $_;
86
                            utf8::decode($filter_str);
87
                            my $quotes_existed = ( $filter_str =~ m/^".*"$/ );
88
                            $filter_str =~ s/^"(.*)"$/$1/; #remove quote around value if exist
89
                            $filter_str =~ s/[^\\]\K"/\\"/g;
90
                            $filter_str = qq{"$filter_str"} # Add quote around value if not exist
91
                                if not $filter_str =~ /^".*"$/
92
                                    and $quotes_existed;
93
                            qq{$idx:$filter_str};
94
                        } @{ $filters->{$idx} } )
95
                    . ')'
96
                : "$idx:$filters->{$idx}";
97
        } keys %$filters
98
    ];
99
100
    my $sq = Data::SearchEngine::Query->new(
101
        page  => $page,
102
        count => $count,
103
        query => $q,
104
    );
105
106
    # Get results
107
    my $results = eval { $self->searchengine->search( $sq ) };
108
109
    # Get error if exists
110
    if ( $@ ) {
111
        my $err = $@;
112
113
        $err =~ s#^[^\n]*\n##; # Delete first line
114
        if ( $err =~ "400 URL must be absolute" ) {
115
            $err = "Your system preference 'SolrAPI' is not set correctly";
116
        }
117
        elsif ( not $err =~ 'Connection refused' ) {
118
            my $document = XMLin( $err );
119
            $err = "$$document{body}{h2} : $$document{body}{pre}";
120
        }
121
        $results->{error} = $err;
122
    }
123
    return $results;
124
}
125
126
sub dosmth {'bou' }
127
128
1;
(-)a/Koha/SearchEngine/Zebra.pm (-32 lines)
Lines 1-32 Link Here
1
package Koha::SearchEngine::Zebra;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose;
21
22
extends 'Data::SearchEngine::Zebra';
23
24
# the configuration file is retrieved from KOHA_CONF by default, provide it from there²
25
has '+conf_file' => (
26
    is => 'ro',
27
    isa => 'Str',
28
    default =>  $ENV{KOHA_CONF},
29
    required => 1
30
);
31
32
1;
(-)a/Koha/SearchEngine/Zebra/QueryBuilder.pm (-31 lines)
Lines 1-31 Link Here
1
package Koha::SearchEngine::Zebra::QueryBuilder;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Moose::Role;
22
use C4::Search;
23
24
with 'Koha::SearchEngine::QueryBuilderRole';
25
26
sub build_query {
27
    shift;
28
    C4::Search::buildQuery @_;
29
}
30
31
1;
(-)a/Koha/SearchEngine/Zebra/Search.pm (-58 lines)
Lines 1-58 Link Here
1
package Koha::SearchEngine::Zebra::Search;
2
3
# This file is part of Koha.
4
#
5
# Copyright 2012 BibLibre
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Moose::Role;
21
with 'Koha::SearchEngine::SearchRole';
22
23
use Data::SearchEngine::Zebra;
24
use Data::SearchEngine::Query;
25
use Koha::SearchEngine::Zebra;
26
use Data::Dump qw(dump);
27
28
has searchengine => (
29
    is => 'rw',
30
    isa => 'Koha::SearchEngine::Zebra',
31
    default => sub { Koha::SearchEngine::Zebra->new },
32
    lazy => 1
33
);
34
35
sub search {
36
    my ($self,$query_string) = @_;
37
38
     my $query = Data::SearchEngine::Query->new(
39
       count => 10,
40
       page => 1,
41
       query => $query_string,
42
     );
43
44
    warn "search for $query_string";
45
46
    my $results = $self->searchengine->search($query);
47
48
    foreach my $item (@{ $results->items }) {
49
        my $title = $item->get_value('ste_title');
50
        #utf8::encode($title);
51
        print "$title\n";
52
                warn dump $title;
53
    }
54
}
55
56
sub dosmth {'bou' }
57
58
1;
(-)a/admin/admin-home.pl (-2 lines)
Lines 34-39 my ($template, $loggedinuser, $cookie) Link Here
34
			     debug => 1,
34
			     debug => 1,
35
			     });
35
			     });
36
36
37
$template->param( SearchEngine => C4::Context->preference('SearchEngine') );
38
39
output_html_with_http_headers $query, $cookie, $template->output;
37
output_html_with_http_headers $query, $cookie, $template->output;
(-)a/admin/searchengine/solr/indexes.pl (-103 lines)
Lines 1-103 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 BibLibre SARL
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
use Modern::Perl;
21
use CGI;
22
use C4::Koha;
23
use C4::Output;
24
use C4::Auth;
25
use Koha::SearchEngine;
26
27
my $input = new CGI;
28
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
29
    {
30
        template_name   => 'admin/searchengine/solr/indexes.tt',
31
        query           => $input,
32
        type            => 'intranet',
33
#        authnotrequired => 0,
34
#        flagsrequired   => { reserveforothers => "place_holds" }, #TODO
35
    }
36
);
37
38
my $ressource_type = $input->param('ressource_type') || 'biblio';
39
my $se = Koha::SearchEngine->new;
40
my $se_config = $se->config;
41
42
my $indexes;
43
if ( $input->param('op') and $input->param('op') eq 'edit' ) {
44
    my @code            = $input->param('code');
45
    my @label           = $input->param('label');
46
    my @type            = $input->param('type');
47
    my @sortable        = $input->param('sortable');
48
    my @facetable       = $input->param('facetable');
49
    my @mandatory       = $input->param('mandatory');
50
    my @ressource_type  = $input->param('ressource_type');
51
    my @mappings        = $input->param('mappings');
52
    my @indexes;
53
    my @errors;
54
    for ( 0 .. @code-1 ) {
55
        my $icode = $code[$_];
56
        my @current_mappings = split /\r\n/, $mappings[$_];
57
        if ( not @current_mappings ) {
58
            @current_mappings = split /\n/, $mappings[$_];
59
        }
60
        if ( not @current_mappings ) {
61
            push @errors, { type => 'no_mapping', value => $icode};
62
        }
63
64
        push @indexes, {
65
            code           => $icode,
66
            label          => $label[$_],
67
            type           => $type[$_],
68
            sortable       => scalar(grep(/^$icode$/, @sortable)),
69
            facetable      => scalar(grep(/^$icode$/, @facetable)),
70
            mandatory      => $mandatory[$_] eq '1' ? '1' : '0',
71
            ressource_type => $ressource_type[$_],
72
            mappings       => \@current_mappings,
73
        };
74
        for my $m ( @current_mappings ) {
75
            push @errors, {type => 'malformed_mapping', value => $m}
76
                if not $m =~ /^\d(\d|\*|\.){2}\$.$/;
77
        }
78
    }
79
    $indexes = \@indexes if @errors;
80
    $template->param( errors => \@errors );
81
82
    $se_config->indexes(\@indexes) if not @errors;
83
}
84
85
my $ressource_types = $se_config->ressource_types;
86
$indexes //= $se_config->indexes;
87
88
my $indexloop;
89
for my $rt ( @$ressource_types ) {
90
    my @indexes = map {
91
        $_->{ressource_type} eq $rt ? $_ : ();
92
    } @$indexes;
93
    push @$indexloop, {
94
        ressource_type => $rt,
95
        indexes => \@indexes,
96
    }
97
}
98
99
$template->param(
100
    indexloop       => $indexloop,
101
);
102
103
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/debian/rules (-3 lines)
Lines 20-28 override_dh_auto_install: Link Here
20
	rm -r $(TMP)/var/run
20
	rm -r $(TMP)/var/run
21
	rm -r $(TMP)/var/lock
21
	rm -r $(TMP)/var/lock
22
	rm $(TMP)/var/log/koha/README
22
	rm $(TMP)/var/log/koha/README
23
	rm $(TMP)/etc/koha/searchengine/solr/config.yaml
24
	rm $(TMP)/etc/koha/searchengine/solr/indexes.yaml
25
	rm $(TMP)/etc/koha/solr/indexes.yaml
26
	rm -r \
23
	rm -r \
27
		$(TMP)/usr/share/koha/intranet/htdocs/intranet-tmpl/lib/tiny_mce
24
		$(TMP)/usr/share/koha/intranet/htdocs/intranet-tmpl/lib/tiny_mce
28
	ln -s /usr/share/tinymce/www \
25
	ln -s /usr/share/tinymce/www \
(-)a/etc/searchengine/solr/config.yaml (-1 lines)
Line 1 Link Here
1
SolrAPI: 'http://localhost:8983/solr/solr'
(-)a/etc/searchengine/solr/indexes.yaml (-45 lines)
Lines 1-45 Link Here
1
---
2
indexes:
3
  - code: title
4
    facetable: 1
5
    label: Title
6
    mandatory: 1
7
    mappings:
8
      - 200$a
9
      - 210$a
10
      - 4..$t
11
    ressource_type: biblio
12
    sortable: 1
13
    type: ste
14
  - code: author
15
    facetable: 1
16
    label: Author
17
    mandatory: 0
18
    mappings:
19
      - 700$*
20
      - 710$*
21
    ressource_type: biblio
22
    sortable: 1
23
    type: str
24
  - code: subject
25
    facetable: 0
26
    label: Subject
27
    mandatory: 0
28
    mappings:
29
      - 600$a
30
      - 601$a
31
    ressource_type: biblio
32
    sortable: 0
33
    type: str
34
  - code: biblionumber
35
    facetable: 0
36
    label: Biblionumber
37
    mandatory: 1
38
    mappings:
39
      - 001$@
40
    ressource_type: biblio
41
    sortable: 0
42
    type: int
43
ressource_types:
44
  - biblio
45
  - authority
(-)a/etc/searchengine/solr/indexes.yaml.bak (-33 lines)
Lines 1-33 Link Here
1
ressource_types:
2
    - biblio
3
    - authority
4
5
indexes:
6
    - code: title
7
      label: Title
8
      type: ste
9
      ressource_type: biblio
10
      sortable: 1
11
      mandatory: 1
12
      mappings:
13
          - 200$a
14
          - 210$a
15
          - 4..$t
16
    - code: author
17
      label: Author
18
      type: str
19
      ressource_type: biblio
20
      sortable: 1
21
      mandatory: 0
22
      mappings:
23
          - 700$*
24
          - 710$*
25
    - code: subject
26
      label: Subject
27
      type: str
28
      ressource_type: biblio
29
      sortable: 0
30
      mandatory: 0
31
      mappings:
32
          - 600$a
33
          - 601$a
(-)a/installer/data/mysql/sysprefs.sql (-1 lines)
Lines 348-354 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
348
('RoutingSerials','1',NULL,'If ON, serials routing is enabled','YesNo'),
348
('RoutingSerials','1',NULL,'If ON, serials routing is enabled','YesNo'),
349
('SCOUserCSS','',NULL,'Add CSS to be included in the SCO module in an embedded <style> tag.','free'),
349
('SCOUserCSS','',NULL,'Add CSS to be included in the SCO module in an embedded <style> tag.','free'),
350
('SCOUserJS','',NULL,'Define custom javascript for inclusion in the SCO module','free'),
350
('SCOUserJS','',NULL,'Define custom javascript for inclusion in the SCO module','free'),
351
('SearchEngine','Zebra','Solr|Zebra','Search Engine','Choice'),
352
('SearchMyLibraryFirst','0',NULL,'If ON, OPAC searches return results limited by the user\'s library by default if they are logged in','YesNo'),
351
('SearchMyLibraryFirst','0',NULL,'If ON, OPAC searches return results limited by the user\'s library by default if they are logged in','YesNo'),
353
('SelfCheckHelpMessage','','70|10','Enter HTML to include under the basic Web-based Self Checkout instructions on the Help page','Textarea'),
352
('SelfCheckHelpMessage','','70|10','Enter HTML to include under the basic Web-based Self Checkout instructions on the Help page','Textarea'),
354
('SelfCheckReceiptPrompt','1','NULL','If ON, print receipt dialog pops up when self checkout is finished','YesNo'),
353
('SelfCheckReceiptPrompt','1','NULL','If ON, print receipt dialog pops up when self checkout is finished','YesNo'),
(-)a/installer/data/mysql/updatedatabase.pl (+9 lines)
Lines 8776-8781 if ( CheckVersion($DBversion) ) { Link Here
8776
    SetVersion($DBversion);
8776
    SetVersion($DBversion);
8777
}
8777
}
8778
8778
8779
$DBversion = "3.17.00.XXX";
8780
if ( CheckVersion($DBversion) ) {
8781
    $dbh->do(q{
8782
        DELETE FROM systempreferences WHERE variable = 'SearchEngine'
8783
    });
8784
    print "Upgrade to $DBversion done (Bug 12538 - Remove SearchEngine syspref)\n";
8785
    SetVersion($DBversion);
8786
}
8787
8779
=head1 FUNCTIONS
8788
=head1 FUNCTIONS
8780
8789
8781
=head2 TableExists($table)
8790
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt (-4 lines)
Lines 77-86 Link Here
77
    <dd>Manage rules for automatically matching MARC records during record imports.</dd>
77
    <dd>Manage rules for automatically matching MARC records during record imports.</dd>
78
    <dt><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI sets configuration</a></dt>
78
    <dt><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI sets configuration</a></dt>
79
    <dd>Manage OAI Sets</dd>
79
    <dd>Manage OAI Sets</dd>
80
    [% IF ( SearchEngine != 'Zebra' ) %]
81
      <dt><a href="/cgi-bin/koha/admin/searchengine/solr/indexes.pl">Search engine configuration</a></dt>
82
      <dd>Manage indexes, facets, and their mappings to MARC fields and subfields.</dd>
83
    [% END %]
84
</dl>
80
</dl>
85
81
86
<h3>Acquisition parameters</h3>
82
<h3>Acquisition parameters</h3>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref (-8 lines)
Lines 105-115 Administration: Link Here
105
                  yes: Allow
105
                  yes: Allow
106
                  no: "Don't Allow"
106
                  no: "Don't Allow"
107
            - Mozilla persona for login
107
            - Mozilla persona for login
108
    Search Engine:
109
        -
110
            - pref: SearchEngine
111
              default: Zebra
112
              choices:
113
                Solr: Solr
114
                Zebra: Zebra
115
            - is the search engine used.
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/searchengine/solr/indexes.tt (-222 lines)
Lines 1-222 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Administration &rsaquo; Solr config</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/tablednd.js"></script>
5
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.textarea-expander.js"></script>
6
<script type="text/javascript">
7
    function clean_line( line ) {
8
        $(line).find('input[type="text"]').val("");
9
        $(line).find('input[type="checkbox"]').attr("checked", false);
10
        $(line).find('textarea').val("");
11
        $(line).find('select').find('option:first').attr("selected", "selected");
12
    }
13
14
    function clone_line( line ) {
15
        var new_line = $(line).clone();
16
        $(new_line).removeClass("nodrag nodrop");
17
        $(new_line).find('td:last-child>a').removeClass("add").addClass("delete").html(_("Delete"));
18
        $(new_line).find('[data-id]').each( function() {
19
            $(this).attr({ name: $(this).attr('data-id') }).removeAttr('data-id');
20
        } );
21
        $(new_line).find("select").each( function() {
22
            var attr = $(this).attr('name');
23
            var val = $(line).find('[data-id="' + attr + '"]').val();
24
            $(this).find('option[value="' + val + '"]').attr("selected", "selected");
25
        } );
26
        return new_line;
27
    }
28
29
    $(document).ready(function() {
30
        $('.delete').click(function() {
31
            $(this).parents('tr').remove();
32
        });
33
34
        $(".indexes").tableDnD( {
35
            onDragClass: "dragClass",
36
        } );
37
        $("textarea").TextAreaExpander();
38
        $('.add').click(function() {
39
            var table = $(this).closest('table');
40
            var ressource_type  = $(table).attr('data-ressource_type');
41
            var code            = $(table).find('input[data-id="code"]').val();
42
            var label           = $(table).find('input[data-id="label"]').val();
43
            if ( code.length > 0 && label.length > 0 ) {
44
                var line = $(this).closest("tr");
45
                var mappings = $(line).find('textarea').val();
46
                var new_line = clone_line( line );
47
                $(new_line).find('textarea').val(mappings);
48
                $(new_line).find("input:checkbox").val(code);
49
                new_line.appendTo($('table[data-ressource_type="'+ressource_type+'"]>tbody'));
50
                $('.delete').click(function() {
51
                    $(this).parents('tr').remove();
52
                });
53
                clean_line(line);
54
55
                $(table).tableDnD( {
56
                    onDragClass: "dragClass",
57
                } );
58
            }
59
        });
60
    });
61
</script>
62
</head>
63
<body id="admin_searchengine_indexes" class="admin">
64
[% INCLUDE 'header.inc' %]
65
[% INCLUDE 'cat-search.inc' %]
66
67
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; Search engine configuration</div>
68
69
<div id="doc3" class="yui-t1">
70
71
  <div id="bd">
72
    <div id="yui-main">
73
    <div class="yui-b">
74
    <h1>Search engine configuration</h1>
75
    <div class="warning">
76
        Warning: Any modification in these configurations will need a total reindexation to be fully taken into account !
77
    </div>
78
    [% IF ( errors ) %]
79
        <div class="error">
80
        Errors occurred, Modifications does not apply. Please check following values:
81
          <ul>
82
            [% FOREACH e IN errors %]
83
                <li>
84
                    [% IF ( e.type == "malformed_mapping" ) %]
85
                        The value "[% e.value %]" is not supported for mappings
86
                    [% ELSIF ( e.type == "no_mapping" ) %]
87
                        There is no mapping for the index [% e.value %]
88
                    [% END %]
89
                </li>
90
            [% END %]
91
          </ul>
92
        </div>
93
    [% END %]
94
95
    <form method="post">
96
      <input type="hidden" name="op" value="edit" />
97
      [% FOREACH rt IN indexloop %]
98
        <h2>[% rt.ressource_type %]</h2>
99
        [% IF ( rt.ressource_type == 'authority' ) %]
100
            This part is not yet implemented
101
        [% END %]
102
        <table id="pouet" class="indexes" data-ressource_type="[% rt.ressource_type %]">
103
          <thead>
104
            <tr class="nodrag nodrop">
105
              <th>Code</th>
106
              <th>Label</th>
107
              <th>Type</th>
108
              <th>Sortable</th>
109
              <th>Facetable</th>
110
              <th>Mapping</th>
111
              <th></th>
112
            </tr>
113
          </thead>
114
          <tbody>
115
            [% FOREACH index IN rt.indexes %]
116
              <tr>
117
                <td>
118
                  [% IF ( index.mandatory ) %]
119
                    <input name="code" type="text" maxlength="25" value="[% index.code %]" disabled="disabled" />
120
                    <input name="code" type="hidden" maxlength="25" value="[% index.code %]" />
121
                  [% ELSE %]
122
                    <input name="code" type="text" maxlength="25" value="[% index.code %]" />
123
                  [% END %]
124
                  <input name="mandatory" type="hidden" maxlength="1" value="[% index.mandatory %]" />
125
                  <input name="ressource_type" type="hidden" value="[% index.ressource_type %]" />
126
                </td>
127
                <td><input name="label" type="text" maxlength="25" value="[% index.label %]" /></td>
128
                <td>
129
                  [% IF ( index.mandatory ) %]
130
                    <input type="hidden" name="type" value="[% index.type %]" />
131
                  [% END %]
132
                  [% IF ( index.mandatory ) %]
133
                    <select name="type" disabled="disabled">
134
                  [% ELSE %]
135
                    <select name="type">
136
                  [% END %]
137
                    [% IF ( index.type == 'str' ) %]
138
                        <option value="str" selected="selected">String</option>
139
                    [% ELSE %]
140
                        <option value="str">String</option>
141
                    [% END %]
142
                    [% IF ( index.type == 'ste' ) %]
143
                        <option value="ste" selected="selected">Simple Text</option>
144
                    [% ELSE %]
145
                        <option value="ste">Simple Text</option>
146
                    [% END %]
147
                    [% IF ( index.type == 'txt' ) %]
148
                        <option value="txt" selected="selected">Text</option>
149
                    [% ELSE %]
150
                        <option value="txt">Text</option>
151
                    [% END %]
152
                    [% IF ( index.type == 'int' ) %]
153
                        <option value="int" selected="selected">Integer</option>
154
                    [% ELSE %]
155
                        <option value="int">Integer</option>
156
                    [% END %]
157
                    [% IF ( index.type == 'date' ) %]
158
                        <option value="date" selected="selected">Date</option>
159
                    [% ELSE %]
160
                        <option value="date">Date</option>
161
                    [% END %]
162
                  </select>
163
                </td>
164
                <td>
165
                  [% IF ( index.sortable ) %]
166
                    <input name="sortable" type="checkbox" checked="checked" value="[% index.code %]" />
167
                  [% ELSE %]
168
                    <input name="sortable" type="checkbox" value="[% index.code %]" />
169
                  [% END %]
170
                </td>
171
                <td>
172
                  [% IF ( index.facetable ) %]
173
                    <input name="facetable" type="checkbox" checked="checked" value="[% index.code %]" />
174
                  [% ELSE %]
175
                    <input name="facetable" type="checkbox" value="[% index.code %]" />
176
                  [% END %]
177
                </td>
178
                <td>
179
                    <textarea name="mappings" class="contentEditable">[% FOREACH m IN index.mappings %][% m %]
180
[% END %]</textarea> <!-- Don't indent this line -->
181
                </td>
182
                <td>[% UNLESS ( index.mandatory ) %]<a class="delete">Delete</a>[% END %]</td>
183
              </tr>
184
              [% END %]
185
          </tbody>
186
          <tfoot>
187
            <tr class="nodrag nodrop">
188
              <td>
189
                <input data-id="code" type="text" maxlength="25" />
190
                <input data-id="ressource_type" type="hidden" value="[% rt.ressource_type %]" />
191
                <input data-id="mandatory" type="hidden" value="0" />
192
              </td>
193
              <td><input data-id="label" type="text" maxlength="25" /></td>
194
              <td>
195
                <select data-id="type">
196
                  <option value="str">String</option>
197
                  <option value="ste">Simple Text</option>
198
                  <option value="txt">Text</option>
199
                  <option value="int">Integer</option>
200
                  <option value="date">Date</option>
201
                </select>
202
              </td>
203
              <td><input data-id="sortable" type="checkbox" /></td>
204
              <td><input data-id="facetable" type="checkbox" /></td>
205
              <td>
206
                <textarea data-id="mappings" class="contentEditable"></textarea>
207
              </td>
208
              <td><a class="add">Add</a></td>
209
            </tr>
210
          </tfoot>
211
        </table>
212
      [% END %]
213
      <p><input type="submit" value="Save" /></p>
214
    </form>
215
</div>
216
217
</div>
218
<div class="yui-b">
219
[% INCLUDE 'admin-menu.inc' %]
220
</div>
221
</div>
222
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/opac-tmpl/prog/en/includes/search/facets.inc (-56 lines)
Lines 1-56 Link Here
1
[% IF facets_loop %]
2
  <div id="search-facets">
3
    <h4>Refine your search</h4>
4
    <ul>
5
      [% FOR facets IN facets_loop %]
6
        <li>
7
          [% facets.label %]
8
          <ul class="facets_list">
9
            [% FOR value IN facets.values %]
10
              <li>
11
                [% IF ( value.active ) %]
12
                  [% value.lib %] ([% value.count %])
13
                  [% SET url = "/cgi-bin/koha/opac-search.pl?" %]
14
                  [% SET first = 1 %]
15
                  [% FOR p IN follower_params %]
16
                    [% IF p.var != 'filters' %]
17
                      [% UNLESS first %]
18
                        [% SET url = url _ '&' %]
19
                      [% END %]
20
                      [% SET first = 0 %]
21
                      [% SET url = url _ p.var _ '=' _ p.val %]
22
                    [% END %]
23
                  [% END %]
24
                  [% FOR f IN filters %]
25
                    [% UNLESS f.var == facets.indexname && f.val == value.value %]
26
                      [% SET url = url _ '&filters=' _ f.var _ ':&quot;' _ f.val _ '&quot;' %]
27
                    [% END %]
28
                  [% END %]
29
                  [<a href="[% url |url %]">x</a>]
30
                [% ELSE %]
31
                  [% SET url = "/cgi-bin/koha/opac-search.pl?" %]
32
                  [% SET first = 1 %]
33
                  [% FOR p IN follower_params %]
34
                    [% IF p.var != 'filters' %]
35
                      [% UNLESS first %]
36
                        [% SET url = url _ '&' %]
37
                      [% END %]
38
                      [% SET first = 0 %]
39
                      [% SET url = url _ p.var _ '=' _ p.val %]
40
                    [% END %]
41
                  [% END %]
42
                  [% FOR f IN filters %]
43
                    [% SET url = url _ '&filters=' _ f.var _ ':&quot;' _ f.val _ '&quot;' %]
44
                  [% END %]
45
                  [% SET url = url _ '&filters=' _ facets.indexname _ ':&quot;' _ value.value _ '&quot;' %]
46
47
                  <a href="[% url |url %]">[% value.lib %]</a> ([% value.count %])
48
                [% END %]
49
              </li>
50
            [% END %]
51
          </ul>
52
        </li>
53
      [% END %]
54
    </ul>
55
</div>
56
[% END %]
(-)a/koha-tmpl/opac-tmpl/prog/en/includes/search/page-numbers.inc (-17 lines)
Lines 1-17 Link Here
1
[% IF ( PAGE_NUMBERS ) %]
2
  <div class="pages">
3
    [% IF ( previous_page ) %]
4
      <a class="nav" href="?[% FOREACH fp IN follower_params %][% fp.var |url %]=[% fp.val |url %]&amp;[% END %]page=[% previous_page |url %]">&lt;&lt; Previous</a>
5
    [% END %]
6
    [% FOREACH PAGE_NUMBER IN PAGE_NUMBERS %]
7
      [% IF ( PAGE_NUMBER.current ) %]
8
        <span class="current">[% PAGE_NUMBER.page %]</span>
9
      [% ELSE %]
10
        <a class="nav" href="?[% FOREACH fp IN follower_params %][% fp.var |url %]=[% fp.val |url %]&amp;[% END %]page=[% PAGE_NUMBER.page |url %]">[% PAGE_NUMBER.page %]</a>
11
      [% END %]
12
    [% END %]
13
    [% IF ( next_page ) %]
14
      <a class="nav" href="?[% FOREACH fp IN follower_params %][% fp.var |url %]=[% fp.val |url %]&amp;[% END %]page=[% next_page |url %]">Next &gt;&gt;</a>
15
    [% END %]
16
  </div>
17
[% END %]
(-)a/koha-tmpl/opac-tmpl/prog/en/includes/search/resort_form.inc (-23 lines)
Lines 1-23 Link Here
1
[% IF sort_by == "score asc" %]
2
  <option value="score asc" selected="selected">Relevance asc</option>
3
[% ELSE %]
4
  <option value="score asc">Relevance asc</option>
5
[% END %]
6
[% IF sort_by == "score desc" %]
7
  <option value="score desc" selected="selected">Relevance desc</option>
8
[% ELSE %]
9
  <option value="score desc">Relevance desc</option>
10
[% END %]
11
12
[% FOREACH ind IN sortable_indexes %]
13
  [% IF sort_by == "$ind.code asc" %]
14
    <option value="[% ind.code %] asc" selected="selected">[% ind.label %] asc</option>
15
  [% ELSE %]
16
    <option value="[% ind.code %] asc">[% ind.label %] asc</option>
17
  [% END %]
18
  [% IF sort_by == "$ind.code desc" %]
19
    <option value="[% ind.code %] desc" selected="selected">[% ind.label %] desc</option>
20
  [% ELSE %]
21
    <option value="[% ind.code %] desc">[% ind.label %] desc</option>
22
  [% END %]
23
[% END %]
(-)a/misc/migration_tools/rebuild_solr.pl (-179 lines)
Lines 1-179 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 BibLibre SARL
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
use Modern::Perl;
21
use Data::Dumper;
22
use Getopt::Long;
23
use LWP::Simple;
24
use XML::Simple;
25
26
use C4::Context;
27
use C4::Search;
28
use Koha::SearchEngine::Index;
29
30
$|=1; # flushes output
31
32
if ( C4::Context->preference("SearchEngine") ne 'Solr' ) {
33
    warn "System preference 'SearchEngine' not equal 'Solr'.";
34
    warn "We can not indexing";
35
    exit(1);
36
}
37
38
#Setup
39
40
my ( $reset, $number, $recordtype, $biblionumbers, $optimize, $info, $want_help );
41
GetOptions(
42
    'r'   => \$reset,
43
    'n:s' => \$number,
44
    't:s' => \$recordtype,
45
    'w:s' => \$biblionumbers,
46
    'o'   => \$optimize,
47
    'i'   => \$info,
48
    'h|help' => \$want_help,
49
);
50
my $debug = C4::Context->preference("DebugLevel");
51
my $index_service = Koha::SearchEngine::Index->new;
52
my $solrurl = $index_service->searchengine->config->SolrAPI;
53
54
my $ping = &ping_command;
55
if (!defined $ping) {
56
    print "SolrAPI = $solrurl\n";
57
    print "Solr is Down\n";
58
    exit(1);
59
}
60
61
#Script
62
63
&print_help if ($want_help);
64
&print_info if ($info);
65
if ($reset){
66
  if ($recordtype){
67
      &reset_index("recordtype:".$recordtype);
68
  } else {
69
      &reset_index("*:*");
70
  }
71
}
72
73
if (defined $biblionumbers){
74
    if (not defined $recordtype) { print "You must specify a recordtype\n"; exit 1;}
75
    &index_biblio($_) for split ',', $biblionumbers;
76
} elsif  (defined $recordtype) {
77
    &index_data;
78
    &optimise_index;
79
}
80
81
if ($optimize) {
82
    &optimise_index;
83
}
84
85
#Functions
86
87
sub index_biblio {
88
    my ($biblionumber) = @_;
89
    $index_service->index_record($recordtype, [ $biblionumber ] );
90
}
91
92
sub index_data {
93
    my $dbh = C4::Context->dbh;
94
        $dbh->do('SET NAMES UTF8;');
95
96
    my $query;
97
    if ( $recordtype eq 'biblio' ) {
98
      $query = "SELECT biblionumber FROM biblio ORDER BY biblionumber";
99
    } elsif ( $recordtype eq 'authority' ) {
100
      $query = "SELECT authid FROM auth_header ORDER BY authid";
101
    }
102
    $query .= " LIMIT $number" if $number;
103
104
    my $sth = $dbh->prepare( $query );
105
    $sth->execute();
106
107
    $index_service->index_record($recordtype, [ map { $_->[0] } @{ $sth->fetchall_arrayref } ] );
108
109
    $sth->finish;
110
}
111
112
sub reset_index {
113
    &reset_command;
114
    &commit_command;
115
    $debug eq '2' && &count_all_docs eq 0 && warn  "Index cleaned!"
116
}
117
118
sub commit_command {
119
    my $commiturl = "/update?stream.body=%3Ccommit/%3E";
120
    my $urlreturns = get $solrurl.$commiturl;
121
}
122
123
sub ping_command {
124
    my $pingurl = "/admin/ping";
125
    my $urlreturns = get $solrurl.$pingurl;
126
}
127
128
sub reset_command {
129
    my ($query) = @_;
130
    my $deleteurl = "/update?stream.body=%3Cdelete%3E%3Cquery%3E".$query."%3C/query%3E%3C/delete%3E";
131
    my $urlreturns = get $solrurl.$deleteurl;
132
}
133
134
sub optimise_index {
135
    $index_service->optimize;
136
}
137
138
sub count_all_docs {
139
    my $queryurl = "/select/?q=*:*";
140
    my $urlreturns = get $solrurl.$queryurl;
141
    my $xmlsimple = XML::Simple->new();
142
    my $data = $xmlsimple->XMLin($urlreturns);
143
    return $data->{result}->{numFound};
144
}
145
146
sub print_info {
147
    my $count = &count_all_docs;
148
    print <<_USAGE_;
149
SolrAPI = $solrurl
150
How many indexed documents = $count;
151
_USAGE_
152
}
153
154
sub print_help {
155
    print <<_USAGE_;
156
$0: reindex biblios and/or authorities in Solr.
157
158
Use this batch job to reindex all biblio or authority records in your Koha database.  This job is useful only if you are using Solr search engine.
159
160
Parameters:
161
    -t biblio               index bibliographic records
162
163
    -t authority            index authority records
164
165
    -r                      clear Solr index before adding records to index - use this option carefully!
166
167
    -n 100                  index 100 first records
168
169
    -n "100,2"              index 2 records after 100th (101 and 102)
170
171
    -w 101                  index biblio with biblionumber equals 101
172
173
    -o                      launch optimize command at the end of indexing
174
175
    -i                      gives solr install information: SolrAPI value and count all documents indexed
176
177
    --help or -h            show this message.
178
_USAGE_
179
}
(-)a/opac/opac-search.pl (-9 lines)
Lines 30-44 use Modern::Perl; Link Here
30
use C4::Context;
30
use C4::Context;
31
use List::MoreUtils q/any/;
31
use List::MoreUtils q/any/;
32
32
33
my $searchengine = C4::Context->preference("SearchEngine");
34
if ( $searchengine =~ /^Solr$/ ) {
35
    warn "We use Solr";
36
    require 'opac/search.pl';
37
    exit;
38
} elsif ( $searchengine =~ /^Zebra$/ ) {
39
40
}
41
42
use C4::Output;
33
use C4::Output;
43
use C4::Auth qw(:DEFAULT get_session);
34
use C4::Auth qw(:DEFAULT get_session);
44
use C4::Languages qw(getLanguages);
35
use C4::Languages qw(getLanguages);
(-)a/opac/search.pl (-172 lines)
Lines 1-172 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 BibLibre
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
use Modern::Perl;
21
22
use C4::Context;
23
use CGI;
24
use C4::Auth;
25
use C4::Koha;
26
use C4::Output;
27
use Koha::SearchEngine::Search;
28
use Koha::SearchEngine::QueryBuilder;
29
use Koha::SearchEngine::FacetsBuilder;
30
31
my $cgi = new CGI;
32
33
my $template_name;
34
my $template_type = "basic";
35
if ( $cgi->param("idx") or $cgi->param("q") ) {
36
    $template_name = 'search/results.tt';
37
} else {
38
    $template_name = 'search/advsearch.tt';
39
    $template_type = 'advsearch';
40
}
41
42
# load the template
43
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
44
    {   template_name   => $template_name,
45
        query           => $cgi,
46
        type            => "opac",
47
        authnotrequired => 1,
48
    }
49
);
50
51
my $format = $cgi->param("format") || 'html';
52
53
54
55
56
# load the Type stuff
57
my $itemtypes = GetItemTypes;
58
59
my $page = $cgi->param("page") || 1;
60
my $count = $cgi->param('count') || C4::Context->preference('OPACnumSearchResults') || 20;
61
$count = 5;
62
my $q = $cgi->param("q");
63
my $builder = Koha::SearchEngine::QueryBuilder->new;
64
$q = $builder->build_query( $q );
65
my $search_service = Koha::SearchEngine::Search->new;
66
67
# load the sorting stuff
68
my $sort_by = $cgi->param('sort_by')
69
        || C4::Context->preference('OPACdefaultSortField') . ' ' . C4::Context->preference('OPACdefaultSortOrder');
70
71
my $search_engine_config = Koha::SearchEngine->new->config;
72
my $sortable_indexes = $search_engine_config->sortable_indexes;
73
my ( $sort_indexname, $sort_order );
74
( $sort_indexname, $sort_order ) = ($1, $2) if ( $sort_by =~ m/^(.*) (asc|desc)$/ );
75
my $sort_by_indexname = eval {
76
    [
77
        map {
78
            $_->{code} eq $sort_indexname
79
                ? 'srt_' . $_->{type} . '_' . $_->{code} . ' ' . $sort_order
80
                : ()
81
        } @$sortable_indexes
82
    ]->[0]
83
};
84
85
# This array is used to build facets GUI
86
my %filters;
87
my @tplfilters;
88
for my $filter ( $cgi->param('filters') ) {
89
    next if not $filter;
90
    my ($k, @v) = $filter =~ /(?: \\. | [^:] )+/xg;
91
    my $v = join ':', @v;
92
    push @{$filters{$k}}, $v;
93
    $v =~ s/^"(.*)"$/$1/; # Remove quotes around
94
    push @tplfilters, {
95
        'var' => $k,
96
        'val' => $v,
97
    };
98
}
99
push @{$filters{recordtype}}, 'biblio';
100
101
my $results = $search_service->search(
102
    $q,
103
    \%filters,
104
    {
105
        page => $page,
106
        count => $count,
107
        sort => $sort_by_indexname,
108
        facets => 1,
109
        fl => ["ste_title", "str_author", 'int_biblionumber'],
110
    }
111
);
112
113
if ($results->{error}){
114
    $template->param(query_error => $results->{error});
115
    output_with_http_headers $cgi, $cookie, $template->output, 'html';
116
    exit;
117
}
118
119
120
# populate results with records
121
my @r;
122
for my $searchresult ( @{ $results->items } ) {
123
    my $biblionumber = $searchresult->{values}->{recordid};
124
125
    my $nr;
126
    while ( my ($k, $v) = each %{$searchresult->{values}} ) {
127
        my $nk = $k;
128
        $nk =~ s/^[^_]*_(.*)$/$1/;
129
        $nr->{$nk} = ref $v ? shift @{$v} : $v;
130
    }
131
    push( @r, $nr );
132
}
133
134
# build facets
135
my $facets_builder = Koha::SearchEngine::FacetsBuilder->new;
136
my @facets_loop = $facets_builder->build_facets( $results, $search_engine_config->facetable_indexes, \%filters );
137
138
my $total = $results->{pager}->{total_entries};
139
my $pager = Data::Pagination->new(
140
    $total,
141
    $count,
142
    20,
143
    $page,
144
);
145
146
# params we want to pass for all actions require another query (pagination, sort, facets)
147
my @follower_params = map { {
148
    var => 'filters',
149
    val => $_->{var}.':"'.$_->{val}.'"'
150
} } @tplfilters;
151
push @follower_params, { var => 'q', val => $q};
152
push @follower_params, { var => 'sort_by', val => $sort_by};
153
154
# Pager template params
155
$template->param(
156
    previous_page    => $pager->{'prev_page'},
157
    next_page        => $pager->{'next_page'},
158
    PAGE_NUMBERS     => [ map { { page => $_, current => $_ == $page } } @{ $pager->{'numbers_of_set'} } ],
159
    current_page     => $page,
160
    follower_params  => \@follower_params,
161
    total            => $total,
162
    SEARCH_RESULTS   => \@r,
163
    query            => $q,
164
    count            => $count,
165
    sort_by          => $sort_by,
166
    sortable_indexes => $sortable_indexes,
167
    facets_loop      => \@facets_loop,
168
    filters          => \@tplfilters,
169
);
170
171
my $content_type = ( $format eq 'rss' or $format eq 'atom' ) ? $format : 'html';
172
output_with_http_headers $cgi, $cookie, $template->output, $content_type;
(-)a/t/00-load.t (-1 lines)
Lines 44-50 find( Link Here
44
            return unless $m =~ s/[.]pm$//;
44
            return unless $m =~ s/[.]pm$//;
45
            $m =~ s{^.*/Koha/}{Koha/};
45
            $m =~ s{^.*/Koha/}{Koha/};
46
            $m =~ s{/}{::}g;
46
            $m =~ s{/}{::}g;
47
            return if $m =~ /Koha::SearchEngine/; # Koha::SearchEngine::* are experimental
48
            use_ok($m) || BAIL_OUT("***** PROBLEMS LOADING FILE '$m'");
47
            use_ok($m) || BAIL_OUT("***** PROBLEMS LOADING FILE '$m'");
49
        },
48
        },
50
    },
49
    },
(-)a/t/searchengine/000_conn/conn.t (-23 lines)
Lines 1-23 Link Here
1
use Modern::Perl;
2
use Test::More;
3
use Koha::SearchEngine::Solr;
4
#use Koha::SearchEngine::Zebra;
5
use Koha::SearchEngine::Search;
6
use t::lib::Mocks qw( mock_preference );
7
8
my $se_index = Koha::SearchEngine::Solr->new;
9
ok($se_index->isa('Data::SearchEngine::Solr'), 'Solr is a Solr data searchengine');
10
11
#$se_index = Koha::SearchEngine::Zebra->new;
12
#ok($se_index->isa('Data::SearchEngine::Zebra'), 'Zebra search engine');
13
14
t::lib::Mocks::mock_preference('SearchEngine', 'Solr');
15
$se_index = Koha::SearchEngine::Search->new;
16
ok($se_index->searchengine->isa('Data::SearchEngine::Solr'), 'Solr search engine');
17
18
#t::lib::Mocks::mock_preference('SearchEngine', 'Zebra');
19
#$se_index = Koha::SearchEngine::Search->new;
20
#ok($se_index->searchengine->isa('Data::SearchEngine::Zebra'), 'Zebra search engine');
21
22
23
done_testing;
(-)a/t/searchengine/001_search/search_base.t (-12 lines)
Lines 1-12 Link Here
1
use Test::More;
2
3
use t::lib::Mocks;
4
5
t::lib::Mocks::mock_preference('SearchEngine', 'Solr');
6
use Koha::SearchEngine::Search;
7
my $search_service = Koha::SearchEngine::Search->new;
8
isnt (scalar $search_service->search("fort"), 0, 'test search') ;
9
10
#$search_service->search($query_service->build_query(@,@,@));
11
12
done_testing;
(-)a/t/searchengine/002_index/index_base.t (-15 lines)
Lines 1-15 Link Here
1
use Test::More;
2
use FindBin qw($Bin);
3
4
use t::lib::::Mocks;
5
6
use Koha::SearchEngine::Index;
7
8
t::lib::Mocks::mock_preference('SearchEngine', 'Solr');
9
my $index_service = Koha::SearchEngine::Index->new;
10
system( qq{/bin/cp $FindBin::Bin/../indexes.yaml /tmp/indexes.yaml} );
11
$index_service->searchengine->config->set_config_filename( "/tmp/indexes.yaml" );
12
is ($index_service->index_record("biblio", [2]), 1, 'test search') ;
13
is ($index_service->optimize, 1, 'test search') ;
14
15
done_testing;
(-)a/t/searchengine/003_query/buildquery.t (-44 lines)
Lines 1-44 Link Here
1
use Modern::Perl;
2
use Test::More;
3
use C4::Context;
4
5
use Koha::SearchEngine;
6
use Koha::SearchEngine::QueryBuilder;
7
use t::lib::Mocks;
8
9
my $titleindex = "title";
10
my $authorindex = "author";
11
#my $eanindex = "str_ean";
12
#my $pubdateindex = "date_pubdate";
13
14
my ($operands, $indexes, $operators);
15
16
17
# === Solr part ===
18
@$operands = ('cup', 'rowling');
19
@$indexes = ('ti', 'au');
20
@$operators = ('AND');
21
22
t::lib::Mocks::mock_preference('SearchEngine', 'Solr');
23
my $qs = Koha::SearchEngine::QueryBuilder->new;
24
25
my $se = Koha::SearchEngine->new;
26
is( $se->name, "Solr", "Test searchengine name eq Solr" );
27
28
my $gotsolr = $qs->build_advanced_query($indexes, $operands, $operators);
29
my $expectedsolr = "ti:cup AND au:rowling";
30
is($gotsolr, $expectedsolr, "Test build_query Solr");
31
32
33
# === Zebra part ===
34
t::lib::Mocks::mock_preference('SearchEngine', 'Zebra');
35
$se = Koha::SearchEngine->new;
36
is( $se->name, "Zebra", "Test searchengine name eq Zebra" );
37
$qs = Koha::SearchEngine::QueryBuilder->new;
38
my ( $builterror, $builtquery, $simple_query, $query_cgi, $query_desc, $limit, $limit_cgi, $limit_desc, $stopwords_removed, $query_type ) = $qs->build_query($operators, $operands, $indexes);
39
my $gotzebra = $builtquery;
40
my $expectedzebra = qq{ti,wrdl= cup AND au,wrdl= rowling };
41
is($gotzebra, $expectedzebra, "Test Zebra indexes in 'normal' search");
42
43
44
done_testing;
(-)a/t/searchengine/004_config/load_config.t (-53 lines)
Lines 1-53 Link Here
1
use Modern::Perl;
2
use Test::More;
3
use FindBin qw($Bin);
4
5
use C4::Context;
6
use Koha::SearchEngine;
7
use t::lib::Mocks;
8
9
t::lib::Mocks::mock_preference('SearchEngine', 'Solr');
10
my $se = Koha::SearchEngine->new;
11
is( $se->name, "Solr", "Test searchengine name eq Solr" );
12
13
my $config = $se->config;
14
$config->set_config_filename( "$FindBin::Bin/../indexes.yaml" );
15
my $ressource_types = $config->ressource_types;
16
is ( grep ( /^biblio$/, @$ressource_types ), 1, "Ressource type biblio must to be defined" );
17
is ( grep ( /^authority$/, @$ressource_types ), 1, "Ressource type authority must to be defined" );
18
19
my $indexes = $config->indexes;
20
is ( scalar(@$indexes), 3, "There are 3 indexes configured" );
21
22
my $index1 = @$indexes[0];
23
is ( $index1->{code}, 'title', "My index first have code=title");
24
is ( $index1->{label}, 'Title', "My index first have label=Title");
25
is ( $index1->{type}, 'ste', "My index first have type=ste");
26
is ( $index1->{ressource_type}, 'biblio', "My index first have ressource_type=biblio");
27
is ( $index1->{sortable}, '1', "My index first have sortable=1");
28
is ( $index1->{mandatory}, '1', "My index first have mandatory=1");
29
eq_array ( $index1->{mappings}, ["200\$a", "4..\$t"], "My first index have mappings=[200\$a,4..\$t]");
30
31
system( qq{/bin/cp $FindBin::Bin/../indexes.yaml /tmp/indexes.yaml} );
32
$config->set_config_filename( "/tmp/indexes.yaml" );
33
$indexes = $config->indexes;
34
my $new_index = {
35
    code => 'isbn',
36
    label => 'ISBN',
37
    type => 'str',
38
    ressource_type => 'biblio',
39
    sortable => 0,
40
    mandatory => 0
41
};
42
push @$indexes, $new_index;
43
$config->indexes( $indexes );
44
45
$indexes = $config->indexes;
46
47
my $isbn_index = $config->index( 'isbn' );
48
is( $isbn_index->{code}, 'isbn', 'Index isbn has been written' );
49
50
my $sortable_indexes = $config->sortable_indexes;
51
is ( @$sortable_indexes, 2, "There are 2 sortable indexes" );
52
53
done_testing;
(-)a/t/searchengine/indexes.yaml (-34 lines)
Lines 1-33 Link Here
1
ressource_types:
2
    - biblio
3
    - authority
4
5
indexes:
6
    - code: title
7
      label: Title
8
      type: ste
9
      ressource_type: biblio
10
      sortable: 1
11
      mandatory: 1
12
      mappings:
13
          - 200$a
14
          - 210$a
15
          - 4..$t
16
    - code: author
17
      label: Author
18
      type: str
19
      ressource_type: biblio
20
      sortable: 1
21
      mandatory: 0
22
      mappings:
23
          - 700$*
24
          - 710$*
25
    - code: subject
26
      label: Subject
27
      type: str
28
      ressource_type: biblio
29
      sortable: 0
30
      mandatory: 0
31
      mappings:
32
          - 600$a
33
          - 601$a
34
- 

Return to bug 12538