Merge git://git.koha.org/pub/scm/koha
[koha.git] / admin / matching-rules.pl
1 #! /usr/bin/perl
2 #
3 # Copyright 2007 LibLime
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 with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19 #
20
21 use strict;
22 use CGI;
23 use C4::Auth;
24 use C4::Context;
25 use C4::Output;
26 use C4::Koha;
27 use C4::Matcher;
28
29 my $script_name = "/cgi-bin/koha/admin/matching-rules.pl";
30
31 my $input = new CGI;
32 my $op = $input->param('op');
33
34
35 my ($template, $loggedinuser, $cookie)
36     = get_template_and_user({template_name => "admin/matching-rules.tmpl",
37                  query => $input,
38                  type => "intranet",
39                  authnotrequired => 0,
40                  flagsrequired => {parameters => 1},
41                  debug => 1,
42                  });
43
44 $template->param(script_name => $script_name);
45
46 my $matcher_id = $input->param("matcher_id");
47
48 $template->param(max_matchpoint => 0);
49 $template->param(max_matchcheck => 0);
50 my $display_list = 0;
51 if ($op eq "edit_matching_rule") {
52     edit_matching_rule_form($template, $matcher_id);
53 } elsif ($op eq "edit_matching_rule_confirmed") {
54     add_update_matching_rule($template, $matcher_id);
55     $display_list = 1;
56 } elsif ($op eq "add_matching_rule") {
57     add_matching_rule_form($template);
58 } elsif ($op eq "add_matching_rule_confirmed") {
59     add_update_matching_rule($template, $matcher_id);
60     $display_list = 1;
61 } elsif ($op eq "delete_matching_rule") {
62     delete_matching_rule_form($template, $matcher_id);
63 } elsif ($op eq "delete_matching_rule_confirmed") {
64     delete_matching_rule($template, $matcher_id);
65     $display_list = 1;
66 } else {
67     $display_list = 1;
68 }
69
70 if ($display_list) {
71     matching_rule_list($template);
72 }
73
74 output_html_with_http_headers $input, $cookie, $template->output;
75
76 exit 0;
77
78 sub add_matching_rule_form {
79     my $template = shift;
80
81     $template->param(
82         matching_rule_form => 1,
83         confirm_op => 'add_matching_rule_confirmed',
84         max_matchpoint => 1,
85         max_matchcheck => 1
86     );
87
88 }
89
90 sub add_update_matching_rule {
91     my $template = shift;
92     my $matcher_id = shift;
93
94     # do parsing
95     my $matcher = C4::Matcher->new('biblio', 1000); # FIXME biblio only for now
96     $matcher->code($input->param('code'));
97     $matcher->description($input->param('description'));
98     $matcher->threshold($input->param('threshold'));
99
100     # matchpoints
101     my @mp_nums = sort map { /^mp_(\d+)_search_index/ ? int($1): () } $input->param;
102     foreach my $mp_num (@mp_nums) {
103         my $index = $input->param("mp_${mp_num}_search_index");
104         my $score = $input->param("mp_${mp_num}_score");
105         # components
106         my $components = [];
107         my @comp_nums = sort map { /^mp_${mp_num}_c_(\d+)_tag/ ? int($1): () } $input->param;
108         foreach my $comp_num (@comp_nums) {
109             my $component = {};
110             $component->{'tag'} = $input->param("mp_${mp_num}_c_${comp_num}_tag");
111             $component->{'subfields'} = $input->param("mp_${mp_num}_c_${comp_num}_subfields");
112             $component->{'offset'} = $input->param("mp_${mp_num}_c_${comp_num}_offset");
113             $component->{'length'} = $input->param("mp_${mp_num}_c_${comp_num}_length");
114             # norms
115             $component->{'norms'} = [];
116             my @norm_nums = sort map { /^mp_${mp_num}_c_${comp_num}_n_(\d+)_norm/ ? int($1): () } $input->param;
117             foreach my $norm_num (@norm_nums) {
118                 push @{ $component->{'norms'} }, $input->param("mp_${mp_num}_c_${comp_num}_n_${norm_num}_norm");
119             }
120             push @$components, $component;
121         }
122         $matcher->add_matchpoint($index, $score, $components);
123     }
124
125     # match checks
126     my @mc_nums = sort map { /^mc_(\d+)_id/ ? int($1): () } $input->param;
127     foreach my $mc_num (@mp_nums) {
128         # source components
129         my $src_components = [];
130         my @src_comp_nums = sort map { /^mc_${mc_num}_src_c_(\d+)_tag/ ? int($1): () } $input->param;
131         foreach my $comp_num (@src_comp_nums) {
132             my $component = {};
133             $component->{'tag'} = $input->param("mc_${mc_num}_src_c_${comp_num}_tag");
134             $component->{'subfields'} = $input->param("mc_${mc_num}_src_c_${comp_num}_subfields");
135             $component->{'offset'} = $input->param("mc_${mc_num}_src_c_${comp_num}_offset");
136             $component->{'length'} = $input->param("mc_${mc_num}_src_c_${comp_num}_length");
137             # norms
138             $component->{'norms'} = [];
139             my @norm_nums = sort map { /^mc_${mc_num}_src_c_${comp_num}_n_(\d+)_norm/ ? int($1): () } $input->param;
140             foreach my $norm_num (@norm_nums) {
141                 push @{ $component->{'norms'} }, $input->param("mc_${mc_num}_src_c_${comp_num}_n_${norm_num}_norm");
142             }
143             push @$src_components, $component;
144         }
145         # target components
146         my $tgt_components = [];
147         my @tgt_comp_nums = sort map { /^mc_${mc_num}_tgt_c_(\d+)_tag/ ? int($1): () } $input->param;
148         foreach my $comp_num (@tgt_comp_nums) {
149             my $component = {};
150             $component->{'tag'} = $input->param("mc_${mc_num}_tgt_c_${comp_num}_tag");
151             $component->{'subfields'} = $input->param("mc_${mc_num}_tgt_c_${comp_num}_subfields");
152             $component->{'offset'} = $input->param("mc_${mc_num}_tgt_c_${comp_num}_offset");
153             $component->{'length'} = $input->param("mc_${mc_num}_tgt_c_${comp_num}_length");
154             # norms
155             $component->{'norms'} = [];
156             my @norm_nums = sort map { /^mc_${mc_num}_tgt_c_${comp_num}_n_(\d+)_norm/ ? int($1): () } $input->param;
157             foreach my $norm_num (@norm_nums) {
158                 push @{ $component->{'norms'} }, $input->param("mc_${mc_num}_tgt_c_${comp_num}_n_${norm_num}_norm");
159             }
160             push @$tgt_components, $component;
161         }
162         $matcher->add_required_check($src_components, $tgt_components);
163     }
164     
165     if (defined $matcher_id and $matcher_id =~ /^\d+/) {
166         $matcher->_id($matcher_id);
167         $template->param(edited_matching_rule => $matcher->code());
168     } else {
169         $template->param(added_matching_rule => $matcher->code());
170     }
171     $matcher_id = $matcher->store();
172 }
173
174 sub delete_matching_rule_form {
175     my $template = shift;
176     my $matcher_id = shift;
177
178     my $matcher = C4::Matcher->fetch($matcher_id);
179     $template->param(
180         delete_matching_rule_form => 1,
181         confirm_op => "delete_matching_rule_confirmed",
182         matcher_id => $matcher_id,
183         code => $matcher->code(),
184         description => $matcher->description(),
185     );
186 }
187
188 sub delete_matching_rule {
189     my $template = shift;
190     my $matcher_id = shift;
191
192     my $matcher = C4::Matcher->fetch($matcher_id);
193     $template->param(deleted_matching_rule => $matcher->code(),
194                     );
195     C4::Matcher->delete($matcher_id);
196 }
197
198 sub edit_matching_rule_form {
199     my $template = shift;
200     my $matcher_id = shift;
201
202     my $matcher = C4::Matcher->fetch($matcher_id);
203
204     $template->param(matcher_id => $matcher_id);
205     $template->param(code => $matcher->code());
206     $template->param(description => $matcher->description());
207     $template->param(threshold => $matcher->threshold());
208
209     my $matcher_info = $matcher->dump();
210     my @matchpoints = ();
211     my $mp_num = 0;
212     foreach my $matchpoint (@{ $matcher_info->{'matchpoints'} }) {
213         $mp_num++;
214         my @components = _parse_components($matchpoint->{'components'});
215         push @matchpoints, { 
216             mp_num => $mp_num, 
217             index => $matchpoint->{'index'}, 
218             score => $matchpoint->{'score'},
219             components => \@components
220         };        
221     }
222     $template->param(matchpoints => \@matchpoints);
223
224     my $mc_num = 0;
225     my @matchchecks = ();
226     foreach my $matchcheck (@{ $matcher_info->{'matchchecks'} }) {
227         $mc_num++;
228         my @src_components = _parse_components($matchcheck->{'source_matchpoint'}->{'components'});
229         my @tgt_components = _parse_components($matchcheck->{'target_matchpoint'}->{'components'});
230         push @matchchecks, {
231             mc_num => $mc_num,
232             src_components => \@src_components,
233             tgt_components => \@tgt_components
234         };
235     }
236     $template->param(matchchecks => \@matchchecks);
237
238     $template->param(
239         matching_rule_form => 1,
240         edit_matching_rule => 1,
241         confirm_op => 'edit_matching_rule_confirmed',
242         max_matchpoint => $mp_num,
243         max_matchcheck => $mc_num
244     );
245
246 }
247
248 sub _parse_components {
249     my $components_ref = shift;
250     my @components = ();
251
252     my $comp_num = 0;
253     foreach my $component (@{ $components_ref  }) {
254         $comp_num++;
255         my $norm_num = 0;
256         my @norms;
257         foreach my $norm (@{ $component->{'norms'} }) {
258             $norm_num++;
259             push @norms, { norm_num => $norm_num, norm => $norm };
260         }
261         push @components, {
262             comp_num => $comp_num,
263             tag => $component->{'tag'},
264             subfields => join("", sort keys %{ $component->{'subfields'} }),
265             offset => $component->{'offset'},
266             'length' => $component->{'length'},
267             norms => \@norms
268         };
269     }
270
271     return @components;
272 }
273
274 sub matching_rule_list {
275     my $template = shift;
276     
277     my @matching_rules = C4::Matcher::GetMatcherList();
278     $template->param(available_matching_rules => \@matching_rules);
279     $template->param(display_list => 1);
280 }