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