3 # Copyright 2007 LibLime
5 # This file is part of Koha.
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.
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.
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>.
28 use C4::Matcher qw/valid_normalization_routines/;
30 my $script_name = "/cgi-bin/koha/admin/matching-rules.pl";
32 our $input = CGI->new;
33 my $op = $input->param('op') || '';
36 my ($template, $loggedinuser, $cookie)
37 = get_template_and_user({template_name => "admin/matching-rules.tt",
40 flagsrequired => { parameters => 'manage_matching_rules' },
43 $template->param(script_name => $script_name);
45 my $matcher_id = $input->param("matcher_id");
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 );
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);
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);
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);
74 matching_rule_list($template);
77 output_html_with_http_headers $input, $cookie, $template->output;
81 sub add_matching_rule_form {
85 matching_rule_form => 1,
86 confirm_op => 'add_matching_rule_confirmed',
93 sub add_update_matching_rule {
95 my $matcher_id = shift;
96 my $record_type = $input->param('record_type') || 'biblio';
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'));
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");
111 my @comp_nums = sort map { /^mp_${mp_num}_c_(\d+)_tag/ ? int($1): () } $input->multi_param;
112 foreach my $comp_num (@comp_nums) {
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");
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");
124 push @$components, $component;
126 $matcher->add_matchpoint($index, $score, $components);
130 my @mc_nums = sort map { /^mc_(\d+)_id/ ? int($1): () } $input->multi_param;
131 foreach my $mc_num (@mc_nums) {
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) {
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");
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");
147 push @$src_components, $component;
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) {
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");
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");
164 push @$tgt_components, $component;
166 $matcher->add_required_check($src_components, $tgt_components);
169 if (defined $matcher_id and $matcher_id =~ /^\d+/) {
170 $matcher->_id($matcher_id);
171 $template->param(edited_matching_rule => $matcher->code());
173 $template->param(added_matching_rule => $matcher->code());
175 $matcher_id = $matcher->store();
178 sub delete_matching_rule_form {
179 my $template = shift;
180 my $matcher_id = shift;
182 my $matcher = C4::Matcher->fetch($matcher_id);
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(),
192 sub delete_matching_rule {
193 my $template = shift;
194 my $matcher_id = shift;
196 my $matcher = C4::Matcher->fetch($matcher_id);
197 $template->param(deleted_matching_rule => $matcher->code(),
199 C4::Matcher->delete($matcher_id);
202 sub edit_matching_rule_form {
203 my $template = shift;
204 my $matcher_id = shift;
206 my $matcher = C4::Matcher->fetch($matcher_id);
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();
214 my $matcher_info = $matcher->dump();
215 my @matchpoints = ();
217 foreach my $matchpoint (@{ $matcher_info->{'matchpoints'} }) {
219 my @components = _parse_components($matchpoint->{'components'});
222 index => $matchpoint->{'index'},
223 score => $matchpoint->{'score'},
224 components => \@components
227 $template->param(matchpoints => \@matchpoints);
230 my @matchchecks = ();
231 foreach my $matchcheck (@{ $matcher_info->{'matchchecks'} }) {
233 my @src_components = _parse_components($matchcheck->{'source_matchpoint'}->{'components'});
234 my @tgt_components = _parse_components($matchcheck->{'target_matchpoint'}->{'components'});
237 src_components => \@src_components,
238 tgt_components => \@tgt_components
241 $template->param(matchchecks => \@matchchecks);
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
253 sub _parse_components {
254 my $components_ref = shift;
258 foreach my $component (@{ $components_ref }) {
262 foreach my $norm (@{ $component->{'norms'} }) {
264 push @norms, { norm_num => $norm_num, norm => $norm };
267 comp_num => $comp_num,
268 tag => $component->{'tag'},
269 subfields => join("", sort keys %{ $component->{'subfields'} }),
270 offset => $component->{'offset'},
271 'length' => $component->{'length'},
279 sub matching_rule_list {
280 my $template = shift;
282 my @matching_rules = C4::Matcher::GetMatcherList();
283 $template->param(available_matching_rules => \@matching_rules);
284 $template->param(display_list => 1);