Bug 8015: Add unit tests for SimpleMARC and MarcModificationTemplates routines
authorJonathan Druart <jonathan.druart@biblibre.com>
Fri, 29 Mar 2013 16:29:27 +0000 (17:29 +0100)
committerGalen Charlton <gmc@esilibrary.com>
Thu, 31 Oct 2013 22:50:11 +0000 (22:50 +0000)
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Bug 8015: Fix complains from qa tools

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Bug 8015: Get rid of the eval in ModifyRecordWithTemplate

This patch removes the use of eval in the
C4::MarcModificationTemplates::ModifyRecordWithTemplate routine.

Now this routine call the wanted modification routine with the list of
parameters.
This call is done only if the condition is respected.

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Bug 8015: Get rid of eval for evaluating =~ m//

Koha::SimpleMarc::field_equals uses eval in order to check if a string
matches a pattern.
Now this eval is removed and the "regex" variable does not contain the
regex separated character (/ or |).

Regression: Before this patch, the user was able to user a modifier. Now
it is not possible.

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Bug 8015: Get rid of the eval for substitution

Before this patch, the regex substitution was contain into only one
variable (e.g. my $regex = "/foo/bar/i").
Now each member of the regex is stored into a field in the
marc_modification_template_actions sql table.

In order to avoid a complex code, only modifiers i and g are take into
account.

Note: If you already add the mmta table, you have to drop it.
This patch also adds a foreign key from mmta to mmt tables.

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Bug 8015: FIX ui issue

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Bug 8015: The template name is a required field

Test plan:
Try to add a template with an empty string as name.

Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com>
Signed-off-by: Galen Charlton <gmc@esilibrary.com>
C4/Koha.pm
C4/MarcModificationTemplates.pm
Koha/SimpleMARC.pm
installer/data/mysql/kohastructure.sql
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/modules/tools/marc_modification_templates.tt
t/SimpleMARC.t [new file with mode: 0644]
t/db_dependent/MarcModificationTemplates.t [new file with mode: 0644]
tools/marc_modification_templates.pl

index bb3efc7..fe288d0 100644 (file)
@@ -1498,7 +1498,7 @@ sub _isbn_cleanup {
 sub Log {
   my ($data) = @_;
   warn $data;
-  open my $fh, '>>/tmp/koha.log';
+  open my $fh, '>>', '/tmp/koha.log';
   print $fh "$data\n";
   close $fh;
 }
index 8c9212f..d26b76d 100644 (file)
@@ -1,29 +1,28 @@
 package C4::MarcModificationTemplates;
 
-# Copyright 2010 Kyle M Hall <kyle.m.hall@gmail.com>
-#
 # This file is part of Koha.
 #
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Copyright 2010 Kyle M Hall <kyle.m.hall@gmail.com>
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
 #
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 ## NOTE:
 ## Parts of this module are used from cgi scripts that are detached from apache before
 ## execution. For this reason, the C4::Koha::Log function has been used to capture
 ## output for debugging purposes.
 
-use strict;
-use warnings;
+use Modern::Perl;
 
 use DateTime;
 
@@ -128,7 +127,9 @@ sub AddModificationTemplate {
         $action->{'field_value'},
         $action->{'to_field'},
         $action->{'to_subfield'},
-        $action->{'to_regex'},
+        $action->{'to_regex_search'},
+        $action->{'to_regex_replace'},
+        $action->{'to_regex_modifiers'},
         $action->{'conditional'},
         $action->{'conditional_field'},
         $action->{'conditional_subfield'},
@@ -156,9 +157,6 @@ sub DelModificationTemplate {
   my $dbh = C4::Context->dbh;
   my $sth = $dbh->prepare("DELETE FROM marc_modification_templates WHERE template_id = ?");
   $sth->execute( $template_id );
-
-  $sth = $dbh->prepare("DELETE FROM marc_modification_template_actions WHERE template_id = ?");
-  $sth->execute( $template_id );
 }
 
 =head2
@@ -211,7 +209,7 @@ sub GetModificationTemplateActions {
   AddModificationTemplateAction(
     $template_id, $action, $field_number,
     $from_field, $from_subfield, $field_value,
-    $to_field, $to_subfield, $to_regex,
+    $to_field, $to_subfield, $to_regex_search, $to_regex_replace, $to_regex_modifiers
     $conditional, $conditional_field, $conditional_subfield,
     $conditional_comparison, $conditional_value,
     $conditional_regex, $description
@@ -231,7 +229,9 @@ sub AddModificationTemplateAction {
     $field_value,
     $to_field,
     $to_subfield,
-    $to_regex,
+    $to_regex_search,
+    $to_regex_replace,
+    $to_regex_modifiers,
     $conditional,
     $conditional_field,
     $conditional_subfield,
@@ -243,11 +243,11 @@ sub AddModificationTemplateAction {
 
   C4::Koha::Log( "C4::MarcModificationTemplates::AddModificationTemplateAction( $template_id, $action,
                     $field_number, $from_field, $from_subfield, $field_value, $to_field, $to_subfield,
-                    $to_regex, $conditional, $conditional_field, $conditional_subfield, $conditional_comparison,
+                    $to_regex_search, $to_regex_replace, $to_regex_modifiers, $conditional, $conditional_field, $conditional_subfield, $conditional_comparison,
                     $conditional_value, $conditional_regex, $description )" ) if DEBUG;
   warn( "C4::MarcModificationTemplates::AddModificationTemplateAction( $template_id, $action,
                     $field_number, $from_field, $from_subfield, $field_value, $to_field, $to_subfield,
-                    $to_regex, $conditional, $conditional_field, $conditional_subfield, $conditional_comparison,
+                    $to_regex_search, $to_regex_replace, $to_regex_modifiers, $conditional, $conditional_field, $conditional_subfield, $conditional_comparison,
                     $conditional_value, $conditional_regex, $description )" ) if DEBUG;
 
   $conditional_regex ||= '0';
@@ -270,7 +270,9 @@ sub AddModificationTemplateAction {
   field_value,
   to_field,
   to_subfield,
-  to_regex,
+  to_regex_search,
+  to_regex_replace,
+  to_regex_modifiers,
   conditional,
   conditional_field,
   conditional_subfield,
@@ -279,7 +281,7 @@ sub AddModificationTemplateAction {
   conditional_regex,
   description
   )
-  VALUES ( NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )";
+  VALUES ( NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )";
 
   $sth = $dbh->prepare( $query );
 
@@ -293,7 +295,9 @@ sub AddModificationTemplateAction {
     $field_value,
     $to_field,
     $to_subfield,
-    $to_regex,
+    $to_regex_search,
+    $to_regex_replace,
+    $to_regex_modifiers,
     $conditional,
     $conditional_field,
     $conditional_subfield,
@@ -310,7 +314,7 @@ sub AddModificationTemplateAction {
   ModModificationTemplateAction(
     $mmta_id, $action, $field_number, $from_field,
     $from_subfield, $field_value, $to_field,
-    $to_subfield, $to_regex, $conditional,
+    $to_subfield, $to_regex_search, $to_regex_replace, $to_regex_modifiers, $conditional,
     $conditional_field, $conditional_subfield,
     $conditional_comparison, $conditional_value,
     $conditional_regex, $description
@@ -330,7 +334,9 @@ sub ModModificationTemplateAction {
     $field_value,
     $to_field,
     $to_subfield,
-    $to_regex,
+    $to_regex_search,
+    $to_regex_replace,
+    $to_regex_modifiers,
     $conditional,
     $conditional_field,
     $conditional_subfield,
@@ -351,7 +357,9 @@ sub ModModificationTemplateAction {
   field_value = ?,
   to_field = ?,
   to_subfield = ?,
-  to_regex = ?,
+  to_regex_search = ?,
+  to_regex_replace = ?,
+  to_regex_modifiers = ?,
   conditional = ?,
   conditional_field = ?,
   conditional_subfield = ?,
@@ -371,7 +379,9 @@ sub ModModificationTemplateAction {
     $field_value,
     $to_field,
     $to_subfield,
-    $to_regex,
+    $to_regex_search,
+    $to_regex_replace,
+    $to_regex_modifiers,
     $conditional,
     $conditional_field,
     $conditional_subfield,
@@ -493,82 +503,113 @@ sub ModifyRecordsWithTemplate {
 =cut
 
 sub ModifyRecordWithTemplate {
-  my ( $template_id, $record ) = @_;
-  C4::Koha::Log( "C4::MarcModificationTemplates::ModifyRecordWithTemplate( $template_id, $record )" ) if DEBUG;
-  warn( "C4::MarcModificationTemplates::ModifyRecordWithTemplate( $template_id, $record )" ) if DEBUG;
-  C4::Koha::Log( "Unmodified Record:\n" . $record->as_formatted() ) if DEBUG >= 10;
-  warn( "Unmodified Record:\n" . $record->as_formatted() ) if DEBUG >= 10;
-
-  my $current_date = DateTime->now()->ymd();
-  my $branchcode = C4::Context->userenv->{branch};
-
-  my @actions = GetModificationTemplateActions( $template_id );
-
-  foreach my $a ( @actions ) {
-    my $action = $a->{'action'};
-    my $field_number = $a->{'field_number'};
-    my $from_field = $a->{'from_field'};
-    my $from_subfield = $a->{'from_subfield'};
-    my $field_value = $a->{'field_value'};
-    my $to_field = $a->{'to_field'};
-    my $to_subfield = $a->{'to_subfield'};
-    my $to_regex = $a->{'to_regex'};
-    my $conditional = $a->{'conditional'};
-    my $conditional_field = $a->{'conditional_field'};
-    my $conditional_subfield = $a->{'conditional_subfield'};
-    my $conditional_comparison = $a->{'conditional_comparison'};
-    my $conditional_value = $a->{'conditional_value'};
-    my $conditional_regex = $a->{'conditional_regex'};
-
-    my $eval = "$action( \$record, '$from_field', '$from_subfield', ";
-
-    if ( $field_value ) {
-      C4::Koha::Log( "Field value before replacements: $field_value" ) if ( DEBUG >= 3 );
-      warn( "Field value before replacements: $field_value" ) if ( DEBUG >= 3 );
-
-      $field_value =~ s/__CURRENTDATE__/$current_date/g;
-      $field_value =~ s/__BRANCHCODE__/$branchcode/g;
-
-      $eval .= " undef, " if ( $action eq 'update_field' );
-      $eval .= " '$field_value' ";
-
-      C4::Koha::Log( "Field value after replacements: $field_value" ) if ( DEBUG >= 3 );
-      warn( "Field value after replacements: $field_value" ) if ( DEBUG >= 3 );
-    } elsif ( $to_field ) {
-      $eval .= " '$to_field', '$to_subfield', '$to_regex' ";
-    }
-
-    $eval .= ", '$field_number' " if ( $field_number );
-    $eval .= ') ';
-
-    if ( $conditional ) {
-      $eval .= " $conditional ( ";
-
-      if ( $conditional_comparison eq 'exists' ) {
-        $eval .= "field_exists( \$record, '$conditional_field', '$conditional_subfield' )";
-
-      } elsif ( $conditional_comparison eq 'not_exists' ) {
-        $eval .= "!field_exists( \$record, '$conditional_field', '$conditional_subfield' )";
-
-      } elsif ( $conditional_comparison eq 'equals' ) {
-        $eval .= "field_equals( \$record, '$conditional_value', '$conditional_field', '$conditional_subfield', '$conditional_regex' ) ";
-
-      } elsif ( $conditional_comparison eq 'not_equals' ) {
-        $eval .= "!field_equals( \$record, '$conditional_value', '$conditional_field', '$conditional_subfield', '$conditional_regex' ) ";
-      }
-
-      $eval .= " )";
+    my ( $template_id, $record ) = @_;
+    C4::Koha::Log( "C4::MarcModificationTemplates::ModifyRecordWithTemplate( $template_id, $record )" ) if DEBUG;
+    warn( "C4::MarcModificationTemplates::ModifyRecordWithTemplate( $template_id, $record )" ) if DEBUG;
+    C4::Koha::Log( "Unmodified Record:\n" . $record->as_formatted() ) if DEBUG >= 10;
+    warn( "Unmodified Record:\n" . $record->as_formatted() ) if DEBUG >= 10;
+
+    my $current_date = DateTime->now()->ymd();
+    my $branchcode = C4::Context->userenv->{branch};
+
+    my @actions = GetModificationTemplateActions( $template_id );
+
+    foreach my $a ( @actions ) {
+        my $action = $a->{'action'};
+        my $field_number = $a->{'field_number'};
+        my $from_field = $a->{'from_field'};
+        my $from_subfield = $a->{'from_subfield'};
+        my $field_value = $a->{'field_value'};
+        my $to_field = $a->{'to_field'};
+        my $to_subfield = $a->{'to_subfield'};
+        my $to_regex_search = $a->{'to_regex_search'};
+        my $to_regex_replace = $a->{'to_regex_replace'};
+        my $to_regex_modifiers = $a->{'to_regex_modifiers'};
+        my $conditional = $a->{'conditional'};
+        my $conditional_field = $a->{'conditional_field'};
+        my $conditional_subfield = $a->{'conditional_subfield'};
+        my $conditional_comparison = $a->{'conditional_comparison'};
+        my $conditional_value = $a->{'conditional_value'};
+        my $conditional_regex = $a->{'conditional_regex'};
+
+        if ( $field_value ) {
+            $field_value =~ s/__CURRENTDATE__/$current_date/g;
+            $field_value =~ s/__BRANCHCODE__/$branchcode/g;
+        }
+
+        my @params = ( $record, $from_field, $from_subfield );
+        if ( $action eq 'update_field' ) {
+            push @params,
+                ( $field_value
+                    ? ( undef, $field_value )
+                    : ()
+                );
+        } else {
+            push @params,
+                ( $field_value
+                    ? $field_value
+                    : ()
+                );
+        }
+        push @params, (
+                ( ( not $field_value and $to_field )
+                    ? ( $to_field, $to_subfield, { search => $to_regex_search, replace => $to_regex_replace, modifiers => $to_regex_modifiers} )
+                    : () ),
+                ( $field_number
+                    ? $field_number
+                    : () )
+        );
+
+        my $do = 1;
+        if ( $conditional ) {
+            for ( $conditional_comparison ) {
+                when ( /^exists$/ ) {
+                    my $exists = field_exists( $record, $conditional_field, $conditional_subfield );
+                    $do = $conditional eq 'if'
+                        ? $exists
+                        : not $exists;
+                }
+                when ( /^not_exists$/ ) {
+                    my $exists = field_exists( $record, $conditional_field, $conditional_subfield );
+                    $do = $conditional eq 'if'
+                        ? not $exists
+                        : $exists;
+                }
+                when ( /^equals$/ ) {
+                    my $equals = field_equals( $record, $conditional_value, $conditional_field, $conditional_subfield, $conditional_regex );
+                    $do = $conditional eq 'if'
+                        ? $equals
+                        : not $equals;
+                }
+                when ( /^not_equals$/ ) {
+                    my $equals = field_equals( $record, $conditional_value, $conditional_field, $conditional_subfield, $conditional_regex );
+                    $do = $conditional eq 'if'
+                        ? not $equals
+                        : $equals;
+                }
+            }
+        }
+
+        if ( $do ) {
+            for ( $action ) {
+                when ( /^copy_field$/ ) {
+                    copy_field( @params );
+                }
+                when ( /^update_field$/ ) {
+                    update_field( @params );
+                }
+                when ( /^move_field$/ ) {
+                    move_field( @params );
+                }
+                when ( /^delete_field$/ ) {
+                    delete_field( @params );
+                }
+            }
+        }
+
+        C4::Koha::Log( $record->as_formatted() ) if DEBUG >= 10;
+        warn( $record->as_formatted() ) if DEBUG >= 10;
     }
-
-    $eval .= ";";
-
-    C4::Koha::Log("eval $eval") if DEBUG >= 2;
-    warn("eval $eval") if DEBUG >= 2;
-    eval {$eval};
-    C4::Koha::Log( $record->as_formatted() ) if DEBUG >= 10;
-    warn( $record->as_formatted() ) if DEBUG >= 10;
-
-  }
 }
 1;
 __END__
index f72fc2f..bd4c35e 100644 (file)
@@ -2,8 +2,7 @@ package Koha::SimpleMARC;
 
 # Copyright 2009 Kyle M. Hall <kyle.m.hall@gmail.com>
 
-use strict;
-use warnings;
+use Modern::Perl;
 
 #use MARC::Record;
 
@@ -66,7 +65,7 @@ at your option, any later version of Perl 5 you may have available.
 
   Copies a value from one field to another. If a regular expression ( $regex ) is supplied,
   the value will be transformed by the given regex before being copied into the new field.
-  Example: $regex = 's/Old Text/Replacement Text/'
+  Example: $regex = { search => 'Old Text', replace => 'Replacement Text', modifiers => 'g' };
 
   If $n is passed, copy_field will only copy the Nth field of the list of fields.
   E.g. $n = 1 will only use the first field's value, $n = 2 will use only the 2nd field's value.
@@ -83,15 +82,33 @@ sub copy_field {
   @values = ( $values[$n-1] ) if ( $n );
   C4::Koha::Log( "@values = read_field( $record, $fromFieldName, $fromSubfieldName )" ) if $debug >= 3;
 
-  if ( $regex ) {
+  if ( $regex and $regex->{search} ) {
+    $regex->{modifiers} //= q||;
+    my @available_modifiers = qw( i g );
+    my $modifiers = q||;
+    for my $modifier ( split //, $regex->{modifiers} ) {
+        $modifiers .= $modifier
+            if grep {/$modifier/} @available_modifiers;
+    }
     foreach my $value ( @values ) {
-      C4::Koha::Log( "\$value =~ s$regex" ) if ( $debug >= 3 );
-      eval "\$value =~ s$regex";
+      C4::Koha::Log( "\$value =~ s/$regex->{search}/$regex->{replace}/$modifiers" ) if ( $debug >= 3 );
+        for ( $modifiers ) {
+          when ( /^(ig|gi)$/ ) {
+            $value =~ s/$regex->{search}/$regex->{replace}/ig;
+          }
+          when ( /^i$/ ) {
+            $value =~ s/$regex->{search}/$regex->{replace}/i;
+          }
+          when ( /^g$/ ) {
+            $value =~ s/$regex->{search}/$regex->{replace}/g;
+          }
+          default {
+            $value =~ s/$regex->{search}/$regex->{replace}/;
+          }
+      }
     }
   }
-
   update_field( $record, $toFieldName, $toSubfieldName, $dont_erase, @values );
-
 }
 
 =head2 update_field
@@ -114,21 +131,18 @@ sub update_field {
 
   if ( ! ( $record && $fieldName ) ) { return; }
 
-  if ( @values eq 1 ) {
-    _update_repeatable_field_with_single_value( $record, $fieldName, $subfieldName, @values );
-    return;
-  }
-
   my $i = 0;
   my $field;
   if ( $subfieldName ) {
     if ( my @fields = $record->field( $fieldName ) ) {
       unless ( $dont_erase ) {
+        @values = ($values[0]) x scalar( @fields )
+          if @values == 1;
         foreach my $field ( @fields ) {
           $field->update( "$subfieldName" => $values[$i++] );
         }
       }
-      if ( $i <= scalar @values - 1 ) {
+      if ( $i <= scalar ( @values ) - 1 ) {
         foreach my $field ( @fields ) {
           foreach my $j ( $i .. scalar( @values ) - 1) {
             $field->add_subfields( "$subfieldName" => $values[$j] );
@@ -144,6 +158,8 @@ sub update_field {
     }
   } else { ## No subfield
     if ( my @fields = $record->field( $fieldName ) ) {
+      @values = ($values[0]) x scalar( @fields )
+        if @values == 1;
       foreach my $field ( @fields ) {
         $field->update( $values[$i++] );
       }
@@ -221,7 +237,7 @@ sub field_exists {
   Returns true if the field equals the given value, false otherwise.
 
   If a regular expression ( $regex ) is supplied, the value will be compared using
-  the given regex. Example: $regex = 'm/sought_text/'
+  the given regex. Example: $regex = 'sought_text'
 
   If $n is passed, the Nth field of a repeatable series will be used for comparison.
   Set $n to 1 or leave empty for a non-repeatable field.
@@ -239,8 +255,8 @@ sub field_equals {
   my $field_value = $field_values[$n-1];
 
   if ( $regex ) {
-    C4::Koha::Log( "Testing '$field_value' =~ m$value" ) if $debug >= 3;
-    return eval "\$field_value =~ m$value";
+    C4::Koha::Log( "Testing '$field_value' =~ m/$value/" ) if $debug >= 3;
+    return $field_value =~ m/$value/;
   } else {
     return $field_value eq $value;
   }
@@ -262,7 +278,7 @@ sub field_equals {
 sub move_field {
   my ( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName, $regex, $n ) = @_;
   C4::Koha::Log( "C4::SimpleMARC::move_field( '$record', '$fromFieldName', '$fromSubfieldName', '$toFieldName', '$toSubfieldName', '$regex', '$n' )" ) if $debug;
-  copy_field( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName, $regex, $n , 1);
+  copy_field( $record, $fromFieldName, $fromSubfieldName, $toFieldName, $toSubfieldName, $regex, $n , 'dont_erase' );
   delete_field( $record, $fromFieldName, $fromSubfieldName, $n );
 }
 
@@ -296,45 +312,5 @@ sub delete_field {
   }
 }
 
-=head2 _update_repeatable_field_with_single_value
-
-  _update_repeatable_field_with_single_value( $record, $fieldName, $subfieldName, $value );
-
-  Updates a repeatable field, giving all existing copies of that field the given value.
-
-  This is an internal function, and thus is not exported.
-
-=cut
-
-sub _update_repeatable_field_with_single_value {
-  my ( $record, $fieldName, $subfieldName, $value ) = @_;
-  C4::Koha::Log( "C4::SimpleMARC::_update_repeatable_field_with_single_value( $record, $fieldName, $subfieldName, $value )" ) if $debug;
-
-  if ( ! ( $record && $fieldName ) ) { return; }
-
-  my $field;
-  if ( $subfieldName ) {
-    if ( my @fields = $record->field( $fieldName ) ) {
-      foreach my $field ( @fields ) {
-        $field->update( $subfieldName => $value );
-      }
-    } else {
-      ## Field does not exist, create it.
-      $field = MARC::Field->new( $fieldName, undef, undef, $subfieldName => $value );
-      $record->append_fields( $field );
-    }
-  } else { ## No subfield
-    if ( my @fields = $record->field( $fieldName ) ) {
-      foreach my $field ( @fields ) {
-        $field->update( $value );
-      }
-    } else {
-      ## Field does not exists, create it
-      $field = MARC::Field->new( $fieldName, $value );
-      $record->append_fields( $field );
-    }
-  }
-}
-
 1;
 __END__
index f337a97..fefc985 100644 (file)
@@ -3373,7 +3373,9 @@ CREATE TABLE IF NOT EXISTS marc_modification_template_actions (
   field_value varchar(100) DEFAULT NULL,
   to_field varchar(3) DEFAULT NULL,
   to_subfield varchar(1) DEFAULT NULL,
-  to_regex text,
+  to_regex_search text,
+  to_regex_replace text,
+  to_regex_modifiers varchar(8) DEFAULT '',
   conditional enum('if','unless') DEFAULT NULL,
   conditional_field varchar(3) DEFAULT NULL,
   conditional_subfield varchar(1) DEFAULT NULL,
@@ -3381,7 +3383,8 @@ CREATE TABLE IF NOT EXISTS marc_modification_template_actions (
   conditional_value text,
   conditional_regex tinyint(1) NOT NULL DEFAULT '0',
   description text,
-  PRIMARY KEY (mmta_id)
+  PRIMARY KEY (mmta_id),
+  CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
 
 /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
index 1af6a0f..85128f7 100755 (executable)
@@ -7707,7 +7707,9 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
       field_value varchar(100) default NULL,
       to_field varchar(3) default NULL,
       to_subfield varchar(1) default NULL,
-      to_regex text,
+      to_regex_search text,
+      to_regex_replace text,
+      to_regex_modifiers varchar(8) default '',
       conditional enum('if','unless') default NULL,
       conditional_field varchar(3) default NULL,
       conditional_subfield varchar(1) default NULL,
@@ -7715,7 +7717,8 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
       conditional_value text,
       conditional_regex tinyint(1) NOT NULL default '0',
       description text,
-      PRIMARY KEY  (mmta_id)
+      PRIMARY KEY  (mmta_id),
+      CONSTRAINT `mmta_ibfk_1` FOREIGN KEY (`template_id`) REFERENCES `marc_modification_templates` (`template_id`) ON DELETE CASCADE ON UPDATE CASCADE
       ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
     ");
 
index 00a6e84..1003271 100644 (file)
@@ -9,6 +9,8 @@ $(document).ready(function() {
     $('#select_template').change(function() {
         $('#select_template').submit();
     });
+    $("span.match_regex_prefix" ).hide();
+    $("span.match_regex_suffix" ).hide();
 });
 //]]>
 </script>
@@ -97,9 +99,11 @@ function onToFieldRegexChange( checkboxObj ) {
 
 function onConditionalRegexChange( checkboxObj ) {
     if ( checkboxObj.checked ) {
-        document.getElementById( 'match_regex_prefix' ).style.visibility='visible';
+        $("span.match_regex_prefix" ).show();
+        $("span.match_regex_suffix" ).show();
     } else {
-        document.getElementById( 'match_regex_prefix' ).style.visibility='hidden';
+        $("span.match_regex_prefix" ).hide();
+        $("span.match_regex_suffix" ).hide();
     }
 }
 
@@ -145,7 +149,7 @@ var modaction_legend_innerhtml;
 var action_submit_value;
 
 function editAction( mmta_id, ordering, action, field_number, from_field, from_subfield, field_value, to_field,
-    to_subfield, to_regex, conditional, conditional_field, conditional_subfield,
+    to_subfield, to_regex_search, to_regex_replace, to_regex_modifiers, conditional, conditional_field, conditional_subfield,
     conditional_comparison, conditional_value, conditional_regex, description
 ) {
     document.getElementById('mmta_id').value = mmta_id;
@@ -160,9 +164,11 @@ function editAction( mmta_id, ordering, action, field_number, from_field, from_s
     document.getElementById('field_value').value = field_value;
     document.getElementById('to_field').value = to_field;
     document.getElementById('to_subfield').value = to_subfield;
-    document.getElementById('to_regex').value = to_regex;
+    $("#to_regex_search").val(to_regex_search);
+    $("#to_regex_replace").val(to_regex_replace);
+    $("#to_regex_modifiers").val(to_regex_modifiers);
 
-    document.getElementById('to_field_regex').checked = to_regex.length;
+    document.getElementById('to_field_regex').checked = conditional_regex.length;
     document.getElementById('to_field_regex').onchange();
 
     setSelectByValue( 'conditional', conditional );
@@ -200,7 +206,9 @@ function cancelEditAction() {
     document.getElementById('field_value').value = '';
     document.getElementById('to_field').value = '';
     document.getElementById('to_subfield').value = '';
-    document.getElementById('to_regex').value = '';
+    $("#to_regex_search").val("");
+    $("#to_regex_replace").val("");
+    $("#to_regex_modifiers").val("");
 
     document.getElementById('to_field_regex').checked = false;
     document.getElementById('to_field_regex').onchange();
@@ -245,6 +253,7 @@ function setSelectByValue( selectId, value ) {
 <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; MARC modification templates</div>
 
 <div id="doc3" class="yui-t2">
+  <div id="bd">
     <div id="yui-main">
         <div class="yui-b">
             <h2>MARC modification templates</h2>
@@ -290,19 +299,19 @@ function setSelectByValue( selectId, value ) {
                             <tr>
                                 <td style="white-space:nowrap;">
                                     <a title="Move Action Up" href="marc_modification_templates.pl?op=move_action&amp;where=up&amp;template_id=[% ActionsLoo.template_id %]&amp;mmta_id=[% ActionsLoo.mmta_id %]">
-                                    <img src="/intranet-tmpl/[% theme %]/img/go-up.png" border="0" alt="Go up" />
+                                    <img src="[% interface %]/[% theme %]/img/go-up.png" border="0" alt="Go up" />
                                         </a>
 
                                 <a title="Move Action To Top" href="marc_modification_templates.pl?op=move_action&amp;where=top&amp;template_id=[% ActionsLoo.template_id %]&amp;mmta_id=[% ActionsLoo.mmta_id %]">
-                                    <img src="/intranet-tmpl/[% theme %]/img/go-top.png" border="0" alt="Go top" />
+                                    <img src="[% interface %]/[% theme %]/img/go-top.png" border="0" alt="Go top" />
                                         </a>
 
                                         <a title="Move Action To Bottom" href="marc_modification_templates.pl?op=move_action&amp;where=bottom&amp;template_id=[% ActionsLoo.template_id %]&amp;mmta_id=[% ActionsLoo.mmta_id %]">
-                                    <img src="/intranet-tmpl/[% theme %]/img/go-bottom.png" border="0" alt="Go bottom" />
+                                    <img src="[% interface %]/[% theme %]/img/go-bottom.png" border="0" alt="Go bottom" />
                                         </a>
 
                                         <a title="Move Action Down" href="marc_modification_templates.pl?op=move_action&amp;where=down&amp;template_id=[% ActionsLoo.template_id %]&amp;mmta_id=[% ActionsLoo.mmta_id %]">
-                                    <img src="/intranet-tmpl/[% theme %]/img/go-down.png" border="0" alt="Go down" />
+                                    <img src="[% interface %]/[% theme %]/img/go-down.png" border="0" alt="Go down" />
                                         </a>
                                 </td>
 
@@ -330,8 +339,8 @@ function setSelectByValue( selectId, value ) {
                                     [% IF ( ActionsLoo.to_field ) %]
                                         to [% ActionsLoo.to_field %][% IF ( ActionsLoo.to_subfield ) %]$[% ActionsLoo.to_subfield %][% END %]
 
-                                        [% IF ( ActionsLoo.to_regex ) %]
-                                             using RegEx s<strong>[% ActionsLoo.to_regex %]</strong>
+                                        [% IF ( ActionsLoo.to_regex_search ) %]
+                                             using RegEx s<strong>/[% ActionsLoo.to_regex_search %]/[% ActionsLoo.to_regex_replace %]/[% ActionsLoo.to_regex_modifiers %]</strong>
                                         [% END %]
                                     [% END %]
 
@@ -346,7 +355,7 @@ function setSelectByValue( selectId, value ) {
                                         [% IF ( ActionsLoo.conditional_comparison_equals ) %] matches [% END %]
                                         [% IF ( ActionsLoo.conditional_comparison_not_equals ) %] does not match [% END %]
 
-                                        [% IF ( ActionsLoo.conditional_regex ) %] RegEx m[% END %]<strong>[% ActionsLoo.conditional_value %]</strong>
+                                        [% IF ( ActionsLoo.conditional_regex ) %] RegEx m/[% END %]<strong>[% ActionsLoo.conditional_value %]/</strong>
                                     [% END %]
                                 </td>
                                 <td>[% ActionsLoo.description %]</td>
@@ -360,7 +369,9 @@ function setSelectByValue( selectId, value ) {
                                                     "[% ActionsLoo.field_value |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
                                                     "[% ActionsLoo.to_field |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
                                                     "[% ActionsLoo.to_subfield |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
-                                                    "[% ActionsLoo.to_regex |replace('\\\\', '\\\\') |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
+                                                    "[% ActionsLoo.to_regex_search |replace('\\\\', '\\\\') |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
+                                                    "[% ActionsLoo.to_regex_replace |replace('\\\\', '\\\\') |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
+                                                    "[% ActionsLoo.to_regex_modifiers |replace('\\\\', '\\\\') |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
                                                     "[% ActionsLoo.conditional |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
                                                     "[% ActionsLoo.conditional_field |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
                                                     "[% ActionsLoo.conditional_subfield |replace('\\\\', '\\\\') |replace("'", "\'") |replace('"', '\"') |replace('\n', '\\n') |replace('\r', '\\r') %]",
@@ -411,7 +422,7 @@ function setSelectByValue( selectId, value ) {
                                     <input type="checkbox" name="to_field_regex" id="to_field_regex" onchange="onToFieldRegexChange(this);" />
 
                                     <span name="to_field_regex_value_block" id="to_field_regex_value_block" style="display:none;">
-                                        s<input type="text" name="to_regex" id="to_regex" />
+                                        s/<input type="text" name="to_regex_search" id="to_regex_search" placeholder="regex pattern" />/<input type="text" name="to_regex_replace" id="to_regex_replace" placeholder="regex replacement" />/<input type="text" name="to_regex_modifiers" id="to_regex_modifiers" placeholder="ig" size="3" />
                                     </span>
                                 </sup>
                             </span>
@@ -438,7 +449,7 @@ function setSelectByValue( selectId, value ) {
 
                             <span name="conditional_comparison_block" id="conditional_comparison_block" style="display:none;">
 
-                                <span id="match_regex_prefix" style="visibility:hidden;">m</span><input type="text" id="conditional_value" name="conditional_value" />
+                                <span class="match_regex_prefix">m/</span><input type="text" id="conditional_value" name="conditional_value" /><span class="match_regex_suffix">/</span>
 
                                 <sup>
                                     <label for="conditional_regex">RegEx</label>
@@ -470,8 +481,8 @@ function setSelectByValue( selectId, value ) {
                 <fieldset>
                     <legend>Create a new template</legend>
 
-                    <label for="template_name">Name: </label>
-                    <input name="template_name" id="template_name" type="text" size="30" />
+                    <label for="template_name" class="required">Name: </label>
+                    <input name="template_name" id="template_name" type="text" size="30" required="required" />
 
                     <input type="hidden" name="op" value="create_template" />
                     <input type="submit" value="Create template" />
@@ -489,5 +500,6 @@ function setSelectByValue( selectId, value ) {
     <div class="yui-b">
         [% INCLUDE 'tools-menu.inc' %]
     </div>
+  </div>
 </div>
 [% INCLUDE 'intranet-bottom.inc' %]
diff --git a/t/SimpleMARC.t b/t/SimpleMARC.t
new file mode 100644 (file)
index 0000000..2969bd2
--- /dev/null
@@ -0,0 +1,199 @@
+use Modern::Perl;
+
+use Test::More tests => 37;
+
+use_ok("MARC::Field");
+use_ok("MARC::Record");
+use_ok("Koha::SimpleMARC");
+
+sub new_record {
+    my $record = MARC::Record->new;
+    $record->leader('03174nam a2200445 a 4500');
+    my @fields = (
+        MARC::Field->new(
+            100, '1', ' ',
+            a => 'Knuth, Donald Ervin',
+            d => '1938',
+        ),
+        MARC::Field->new(
+            245, '1', '4',
+            a => 'The art of computer programming',
+            c => 'Donald E. Knuth.',
+        ),
+        MARC::Field->new(
+            650, ' ', '0',
+            a => 'Computer programming.',
+            9 => '462',
+        ),
+        MARC::Field->new(
+            952, ' ', ' ',
+            p => '3010023917',
+            y => 'BK',
+            c => 'GEN',
+            d => '2001-06-25',
+        ),
+    );
+    $record->append_fields(@fields);
+    return $record;
+}
+
+my $record = new_record;
+
+# field_exists
+is( field_exists( $record, '650', 'a'), 'Computer programming.', '650$a exists' );
+is( field_exists( $record, '650', 'b'), undef, '650$b does not exist' );
+
+$record->append_fields(
+    MARC::Field->new(
+        650, ' ', '0',
+        a => 'Computer algorithms.',
+        9 => '463',
+    )
+);
+
+is( field_exists( $record, '650', 'a'), 'Computer programming.', '650$a exists, field_exists returns the first one' );
+
+# read_field
+my @fields_650a = read_field( $record, '650', 'a');
+is( $fields_650a[0], 'Computer programming.', 'first 650$a' );
+is( $fields_650a[1], 'Computer algorithms.', 'second 650$a' );
+is( read_field( $record, '650', 'a', 1 ), 'Computer programming.', 'first 650$a bis' );
+is( read_field( $record, '650', 'a', 2 ), 'Computer algorithms.', 'second 650$a bis' );
+is( read_field( $record, '650', 'a', 3 ), undef, 'There is no 3 650$a' );
+
+# copy_field
+copy_field( $record, '245', 'a', '246', 'a' );
+is_deeply( read_field( $record, '245', 'a' ), 'The art of computer programming', 'After copy 245$a still exists' );
+is_deeply( read_field( $record, '246', 'a' ), 'The art of computer programming', '246$a is a new field' );
+delete_field( $record, '246' );
+is( field_exists( $record, '246', 'a', '246$a does not exist anymore' ), undef );
+
+copy_field( $record, '650', 'a', '651', 'a' );
+my @fields_651a = read_field( $record, '651', 'a' );
+is_deeply( \@fields_651a, ['Computer programming.', 'Computer algorithms.'], 'Copy multivalued field' );
+delete_field( $record, '651' );
+
+copy_field( $record, '650', 'a', '651', 'a', undef, 1 );
+@fields_651a = read_field( $record, '651', 'a' );
+is_deeply( read_field( $record, '651', 'a' ), 'Computer programming.', 'Copy first field 650$a' );
+delete_field( $record, '651' );
+
+copy_field( $record, '650', 'a', '651', 'a', undef, 2 );
+@fields_651a = read_field( $record, '651', 'a' );
+is_deeply( read_field( $record, '651', 'a' ), 'Computer algorithms.', 'Copy second field 650$a' );
+delete_field( $record, '651' );
+
+copy_field( $record, '650', 'a', '651', 'a', { search => 'Computer', replace => 'The art of' } );
+@fields_651a = read_field( $record, '651', 'a' );
+is_deeply( \@fields_651a, ['The art of programming.', 'The art of algorithms.'], 'Copy field using regex' );
+
+copy_field( $record, '650', 'a', '651', 'a', { search => 'Computer', replace => 'The mistake of' } );
+@fields_651a = read_field( $record, '651', 'a' );
+is_deeply( \@fields_651a, ['The mistake of programming.', 'The mistake of algorithms.'], 'Copy fields using regex on existing fields' );
+delete_field( $record, '651' );
+
+copy_field( $record, '650', 'a', '651', 'a', { search => 'Computer', replace => 'The art of' } );
+copy_field( $record, '650', 'a', '651', 'a', { search => 'Computer', replace => 'The mistake of' }, 1, "dont_erase" );
+@fields_651a = read_field( $record, '651', 'a' );
+is_deeply( \@fields_651a, [
+    'The art of programming.',
+    'The mistake of programming.',
+    'The art of algorithms.',
+    'The mistake of programming.'
+], 'Copy first field using regex on existing fields without erase existing values' );
+delete_field( $record, '651' );
+
+copy_field( $record, '650', 'a', '651', 'a', { search => 'Computer', replace => 'The art of' } );
+copy_field( $record, '650', 'a', '651', 'a', { search => 'Computer', replace => 'The mistake of' }, undef , "dont_erase" );
+@fields_651a = read_field( $record, '651', 'a' );
+is_deeply( \@fields_651a, [
+    'The art of programming.',
+    'The mistake of programming.',
+    'The mistake of algorithms.',
+    'The art of algorithms.',
+    'The mistake of programming.',
+    'The mistake of algorithms.'
+], 'Copy fields using regex on existing fields without erase existing values' );
+delete_field( $record, '651' );
+
+# Copy with regex modifiers
+copy_field( $record, '650', 'a', '652', 'a', { search => 'o', replace => 'foo' } );
+my @fields_652a = read_field( $record, '652', 'a' );
+is_deeply( \@fields_652a, ['Cfoomputer programming.', 'Cfoomputer algorithms.'], 'Copy field using regex' );
+
+copy_field( $record, '650', 'a', '653', 'a', { search => 'o', replace => 'foo', modifiers => 'g' } );
+my @fields_653a = read_field( $record, '653', 'a' );
+is_deeply( \@fields_653a, ['Cfoomputer prfoogramming.', 'Cfoomputer algfoorithms.'], 'Copy field using regex' );
+
+copy_field( $record, '650', 'a', '654', 'a', { search => 'O', replace => 'foo', modifiers => 'i' } );
+my @fields_654a = read_field( $record, '654', 'a' );
+is_deeply( \@fields_654a, ['Cfoomputer programming.', 'Cfoomputer algorithms.'], 'Copy field using regex' );
+
+copy_field( $record, '650', 'a', '655', 'a', { search => 'O', replace => 'foo', modifiers => 'gi' } );
+my @fields_655a = read_field( $record, '655', 'a' );
+is_deeply( \@fields_655a, ['Cfoomputer prfoogramming.', 'Cfoomputer algfoorithms.'], 'Copy field using regex' );
+
+# update_field
+update_field( $record, '952', 'p', undef, '3010023918' );
+is_deeply( read_field( $record, '952', 'p' ), '3010023918', 'update existing subfield 952$p' );
+delete_field( $record, '952' );
+update_field( $record, '952', 'p', undef, '3010023918' );
+update_field( $record, '952', 'y', undef, 'BK' );
+is_deeply( read_field( $record, '952', 'p' ), '3010023918', 'create subfield 952$p' );
+is_deeply( read_field( $record, '952', 'y' ), 'BK', 'create subfield 952$k on existing 952 field' );
+$record->append_fields(
+    MARC::Field->new(
+        952, ' ', ' ',
+        p => '3010023917',
+        y => 'BK',
+    ),
+);
+update_field( $record, '952', 'p', undef, '3010023919' );
+my @fields_952p = read_field( $record, '952', 'p' );
+is_deeply( \@fields_952p, ['3010023919', '3010023919'], 'update all subfields 952$p with the same value' );
+
+update_field( $record, '952', 'p', undef, ('3010023917', '3010023918') );
+@fields_952p = read_field( $record, '952', 'p' );
+is_deeply( \@fields_952p, ['3010023917', '3010023918'], 'update all subfields 952$p with the different values' );
+
+# move_field
+$record = new_record;
+my ( @fields_952d, @fields_952c, @fields_954c, @fields_954p);
+$record->append_fields(
+    MARC::Field->new(
+        952, ' ', ' ',
+        p => '3010023917',
+        y => 'BK',
+    ),
+);
+copy_field( $record, '952', 'd', '952', 'd' );
+@fields_952d = read_field( $record, '952', 'd' );
+is_deeply( \@fields_952d, ['2001-06-25', '2001-06-25'], 'copy 952$d into others 952 field' );
+
+move_field( $record, '952', 'c', '954', 'c' );
+@fields_952c = read_field( $record, '952', 'c' );
+@fields_954c = read_field( $record, '954', 'c' );
+is_deeply( \@fields_952c, [], 'The 952$c has moved' );
+is_deeply( \@fields_954c, ['GEN'], 'Now 954$c exists' );
+
+move_field( $record, '952', 'p', '954', 'p', undef, 1 ); # Move the first field
+@fields_952p = read_field( $record, '952', 'p' );
+@fields_954p = read_field( $record, '954', 'p' );
+is_deeply( \@fields_952p, ['3010023917'], 'One of 952$p has moved' );
+is_deeply( \@fields_954p, ['3010023917'], 'Now 954$p exists' );
+
+$record = new_record;
+$record->append_fields(
+    MARC::Field->new(
+        952, ' ', ' ',
+        p => '3010023917',
+        y => 'BK',
+    ),
+);
+
+move_field( $record, '952', 'p', '954', 'p' ); # Move all field
+@fields_952p = read_field( $record, '952', 'p' );
+@fields_954p = read_field( $record, '954', 'p' );
+is_deeply( \@fields_952p, [], 'All 952$p have moved' );
+is_deeply( \@fields_954p, ['3010023917', '3010023917'], 'Now 2 954$p exist' );
+
diff --git a/t/db_dependent/MarcModificationTemplates.t b/t/db_dependent/MarcModificationTemplates.t
new file mode 100644 (file)
index 0000000..04ff80a
--- /dev/null
@@ -0,0 +1,262 @@
+use Modern::Perl;
+
+use Test::More tests => 74;
+
+use_ok("MARC::Field");
+use_ok("MARC::Record");
+use_ok("C4::MarcModificationTemplates");
+
+my $dbh = C4::Context->dbh;
+$dbh->{AutoCommit} = 0;
+$dbh->{RaiseError} = 1;
+
+$dbh->do(q|DELETE FROM marc_modification_templates|);
+
+# Creation
+my $template_id = AddModificationTemplate("template_name");
+like( $template_id, qr|^\d+$|, "new template returns an id" );
+
+is( AddModificationTemplateAction(
+    $template_id, 'move_field', 1,
+    '464', 'u', '', '464', '3',
+    '', '', '',
+    '', '', '', '', '', '',
+    'move first 464$u to 464$3'
+), 1, "Add first action");
+
+is( AddModificationTemplateAction(
+    $template_id, 'update_field', 0,
+    '099', 't', 'LIV', '', '',
+    '', '', '',
+    'if', '200', 'b', 'equals', 'Text', '',
+    'Update field 099$t with value LIV if 200$b matches "Text"'
+), 1, "Add second action");
+
+is( AddModificationTemplateAction(
+    $template_id, 'copy_field', 0,
+    '606', 'a', '', '607', 'a',
+    '', '', '',
+    'unless', '606', 'a', 'not_equals', '^AJAX', '1',
+    'Copy field 606$a to 607$a unless 606$a matches RegEx m^AJAX'
+), 1, "Add third action");
+
+# Getter
+my @actions = GetModificationTemplateActions( $template_id );
+is( @actions, 3, "3 actions are insered");
+
+for my $action ( @actions ) {
+    isnt( GetModificationTemplateAction( $action->{mmta_id} ), undef, "action with id $action->{mmta_id} exists" );
+}
+
+my $first_action = $actions[0];
+is( $first_action->{ordering}, 1, "test ordering for first action" );
+is( $first_action->{action}, 'move_field', "test action for first action" );
+is( $first_action->{from_field}, '464', "test from_field for first action" );
+is( $first_action->{from_subfield}, 'u', "test from_subfield for first action" );
+is( $first_action->{to_field}, '464', "test to_field for first action" );
+is( $first_action->{to_subfield}, '3', "test to_subfield for first action" );
+
+my $second_action = $actions[1];
+is( $second_action->{ordering}, 2, "test ordering for second action" );
+is( $second_action->{action}, 'update_field', "test action for second action" );
+is( $second_action->{from_field}, '099',"test from_field for second action" );
+is( $second_action->{from_subfield}, 't', "test from_subfield for second action" );
+is( $second_action->{field_value}, 'LIV', "test firld_value for second action" );
+is( $second_action->{to_field}, '', "test to_field for second action" );
+is( $second_action->{to_subfield}, '', "test to_subfield for second action" );
+is( $second_action->{conditional}, 'if', "test conditional for second action" );
+is( $second_action->{conditional_field}, '200', "test conditional_field for second action" );
+is( $second_action->{conditional_subfield}, 'b', "test conditional_subfield for second action" );
+is( $second_action->{conditional_comparison}, 'equals', "test conditional_comparison for second action" );
+
+my $third_action = $actions[2];
+is( $third_action->{ordering}, 3, "test ordering for third action" );
+is( $third_action->{action}, 'copy_field', "test  factionor third action" );
+is( $third_action->{from_field}, '606', "test from_field for third action" );
+is( $third_action->{from_subfield}, 'a', "test from_subfield for third action" );
+is( $third_action->{to_field}, '607', "test to_field for third action" );
+is( $third_action->{to_subfield}, 'a', "test to_subfield for third action" );
+is( $third_action->{conditional}, 'unless', "test conditional for third action" );
+is( $third_action->{conditional_field}, '606', "test conditional_field for third action" );
+is( $third_action->{conditional_subfield}, 'a', "test conditional_subfield for third action" );
+is( $third_action->{conditional_comparison}, 'not_equals', "test conditional_comparison for third action" );
+is( $third_action->{conditional_value}, '^AJAX', "test conditional_value for third action" );
+
+
+# Modifications
+is( ModModificationTemplateAction(
+    $actions[1]->{mmta_id}, 'update_field', 0,
+    '100', 'u', 'LIV', '', '',
+    '', '', '',
+    'if', '200', 'c', 'equals', 'Text', '',
+    'Update field 099$t with value LIV if 200$b matches "Text"'
+), 1, "Modify second action");
+
+$second_action = GetModificationTemplateAction( $actions[1]->{mmta_id} );
+is( $second_action->{ordering}, 2, "test ordering for second action modified" );
+is( $second_action->{action}, 'update_field', "test action for second action modified" );
+is( $second_action->{from_field}, '100',"test from_field for second action modified" );
+is( $second_action->{from_subfield}, 'u', "test from_subfield for second action modified" );
+is( $second_action->{field_value}, 'LIV', "test firld_value for second action modified" );
+is( $second_action->{to_field}, '', "test to_field for second action modified" );
+is( $second_action->{to_subfield}, '', "test to_subfield for second action modified" );
+is( $second_action->{conditional}, 'if', "test conditional for second action modified" );
+is( $second_action->{conditional_field}, '200', "test conditional_field for second action modified" );
+is( $second_action->{conditional_subfield}, 'c', "test conditional_subfield for second action modified" );
+is( $second_action->{conditional_comparison}, 'equals', "test conditional_comparison for second action modified" );
+
+# Up and down
+is( MoveModificationTemplateAction( $actions[2]->{mmta_id}, 'top' ), '1', 'Move the third action on top' );
+is( MoveModificationTemplateAction( $actions[0]->{mmta_id}, 'bottom' ), '1', 'Move the first action on bottom' );
+
+is( GetModificationTemplateAction( $actions[0]->{mmta_id} )->{ordering}, '3', 'First becomes third' );
+is( GetModificationTemplateAction( $actions[1]->{mmta_id} )->{ordering}, '2', 'Second stays second' );
+is( GetModificationTemplateAction( $actions[2]->{mmta_id} )->{ordering}, '1', 'Third becomes first' );
+
+is( MoveModificationTemplateAction( $actions[0]->{mmta_id}, 'up' ), '1', 'Move up the first action (was third)' );
+is( MoveModificationTemplateAction( $actions[0]->{mmta_id}, 'up' ), '1', 'Move up the first action (was second)' );
+is( MoveModificationTemplateAction( $actions[2]->{mmta_id}, 'down' ), '1', 'Move down the third action (was second)' );
+
+is( GetModificationTemplateAction( $actions[0]->{mmta_id} )->{ordering}, '1', 'First becomes again first' );
+is( GetModificationTemplateAction( $actions[1]->{mmta_id} )->{ordering}, '2', 'Second stays again second' );
+is( GetModificationTemplateAction( $actions[2]->{mmta_id} )->{ordering}, '3', 'Third becomes again third' );
+
+# Cleaning
+is( DelModificationTemplateAction( $actions[0]->{mmta_id} ), 2, "Delete the first action, 2 others are reordered" );
+is( GetModificationTemplateAction( $actions[0]->{mmta_id} ), undef, "first action does not exist anymore" );
+
+is( DelModificationTemplate( $template_id ), 1, "The template has been deleted" );
+
+is( GetModificationTemplateAction( $actions[1]->{mmta_id} ), undef, "second action does not exist anymore" );
+is( GetModificationTemplateAction( $actions[2]->{mmta_id} ), undef, "third action does not exist anymore" );
+
+is( GetModificationTemplateActions( $template_id ), 0, "There is no action for deleted template" );
+
+# ModifyRecordWithTemplate
+my @USERENV = (
+    1,
+    'test',
+    'MASTERTEST',
+    'Test',
+    'Test',
+    't',
+    'Test',
+    0,
+);
+C4::Context->_new_userenv ('DUMMY_SESSION_ID');
+C4::Context->set_userenv ( @USERENV );
+
+$template_id = AddModificationTemplate("template_name");
+like( $template_id, qr|^\d+$|, "new template returns an id" );
+
+is( AddModificationTemplateAction(
+    $template_id, 'copy_field', 0,
+    '245', 'a', '', '246', 'a',
+    '', '', '',
+    '', '', '', '', '', '',
+    'copy field 245$a to 246$a'
+), 1, 'Add first action: copy 245$a to 246$a');
+
+is( AddModificationTemplateAction(
+    $template_id, 'delete_field', 0,
+    '650', 'a', '', '', '',
+    '', '', '',
+    'if', '650', '9', 'equals', '462', '',
+    'Delete field 650$a if 650$9=462'
+), 1, 'Add second action: delete field 650$a if 650$9=462');
+
+is( AddModificationTemplateAction(
+    $template_id, 'update_field', 0,
+    '952', 'p', '3010023917_updated', '', '',
+    '', '', '',
+    'unless', '650', '9', 'equals', '42', '',
+    'Update field 952$p with "3010023917_updated" if 650$9 != 42'
+), 1, 'Add third action: update field 952$p with "3010023917_updated" if 650$9 != 42');
+
+is( AddModificationTemplateAction(
+    $template_id, 'move_field', 0,
+    '952', 'd', '', '952', 'e', '',
+    '', '', '',
+    'if', '952', 'c', 'equals', '^GEN', '1',
+    'Move field 952$d to 952$e if 952$c =~ /^GE/'
+), 1, 'Add fourth action: move field 952$d to 952$e if 952$c =~ /^GE/');
+
+my $record = new_record();
+
+ModifyRecordWithTemplate( $template_id, $record );
+
+my $expected_record = expected_record();
+is_deeply( $record, $expected_record );
+
+done_testing;
+
+sub new_record {
+    my $record = MARC::Record->new;
+    $record->leader('03174nam a2200445 a 4500');
+    my @fields = (
+        MARC::Field->new(
+            100, '1', ' ',
+            a => 'Knuth, Donald Ervin',
+            d => '1938',
+        ),
+        MARC::Field->new(
+            245, '1', '4',
+            a => 'The art of computer programming',
+            c => 'Donald E. Knuth.',
+        ),
+        MARC::Field->new(
+            650, ' ', '0',
+            a => 'Computer programming.',
+            9 => '462',
+        ),
+        MARC::Field->new(
+            952, ' ', ' ',
+            p => '3010023917',
+            y => 'BK',
+            c => 'GEN',
+            d => '2001-06-25',
+        ),
+    );
+    $record->append_fields(@fields);
+    return $record;
+}
+
+sub expected_record {
+    my $record = MARC::Record->new;
+    $record->leader('03174nam a2200445 a 4500');
+    my @fields = (
+        MARC::Field->new(
+            100, '1', ' ',
+            a => 'Knuth, Donald Ervin',
+            d => '1938',
+        ),
+        MARC::Field->new(
+            245, '1', '4',
+            a => 'The art of computer programming',
+            c => 'Donald E. Knuth.',
+        ),
+        MARC::Field->new(
+            650, ' ', '0',
+            9 => '462',
+        ),
+        MARC::Field->new(
+            952, ' ', ' ',
+            p => '3010023917_updated',
+            y => 'BK',
+            c => 'GEN',
+            e => '2001-06-25',
+        ),
+        MARC::Field->new(
+            246, '', ' ',
+            a => 'The art of computer programming',
+        ),
+    );
+    $record->append_fields(@fields);
+    return $record;
+}
+
+
+# C4::Context->userenv
+sub Mock_userenv {
+    return { branchcode => 'CPL' };
+}
index dde2476..e815f60 100755 (executable)
@@ -1,23 +1,22 @@
 #!/usr/bin/perl
-# Copyright 2010 Kyle M Hall <kyle.m.hall@gmail.com>
-#
 # This file is part of Koha.
 #
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Copyright 2010 Kyle M Hall <kyle.m.hall@gmail.com>
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
 #
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
-use strict;
-use warnings;
+use Modern::Perl;
 
 use CGI;
 
@@ -28,7 +27,7 @@ use C4::MarcModificationTemplates;
 
 my $cgi = new CGI;
 
-my $op = $cgi->param('op');
+my $op = $cgi->param('op') || q{};
 my $template_id = $cgi->param('template_id');
 
 my ($template, $loggedinuser, $cookie)
@@ -60,7 +59,9 @@ if ( $op eq "create_template" ) {
   my $field_value = $cgi->param('field_value');
   my $to_field = $cgi->param('to_field');
   my $to_subfield = $cgi->param('to_subfield');
-  my $to_regex = $cgi->param('to_regex');
+  my $to_regex_search = $cgi->param('to_regex_search');
+  my $to_regex_replace = $cgi->param('to_regex_replace');
+  my $to_regex_modifiers = $cgi->param('to_regex_modifiers');
   my $conditional = $cgi->param('conditional');
   my $conditional_field = $cgi->param('conditional_field');
   my $conditional_subfield = $cgi->param('conditional_subfield');
@@ -79,7 +80,9 @@ if ( $op eq "create_template" ) {
       $field_value,
       $to_field,
       $to_subfield,
-      $to_regex,
+      $to_regex_search,
+      $to_regex_replace,
+      $to_regex_modifiers,
       $conditional,
       $conditional_field,
       $conditional_subfield,
@@ -98,7 +101,9 @@ if ( $op eq "create_template" ) {
       $field_value,
       $to_field,
       $to_subfield,
-      $to_regex,
+      $to_regex_search,
+      $to_regex_replace,
+      $to_regex_modifiers,
       $conditional,
       $conditional_field,
       $conditional_subfield,