Bug 31535: Fix warning - uninitialized value $mode in string ne (addbiblio.pl)
[srvgit] / Koha / SimpleMARC.pm
index 991d8a9..6fd08b1 100644 (file)
@@ -2,32 +2,39 @@ package Koha::SimpleMARC;
 
 # Copyright 2009 Kyle M. Hall <kyle.m.hall@gmail.com>
 
-use Modern::Perl;
-
-#use MARC::Record;
-
-require Exporter;
-
-our @ISA = qw(Exporter);
-our %EXPORT_TAGS = ( 'all' => [ qw(
-
-) ] );
-
-our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
-our @EXPORT = qw(
-  read_field
-  update_field
-  copy_field
-  move_field
-  delete_field
-  field_exists
-  field_equals
-);
 
-our $VERSION = '0.01';
+use Modern::Perl;
 
-our $debug = 0;
+our (@ISA, @EXPORT_OK);
+BEGIN {
+    require Exporter;
+    our @ISA = qw(Exporter);
+
+    @EXPORT_OK = qw(
+      read_field
+      add_field
+      update_field
+      copy_field
+      copy_and_replace_field
+      move_field
+      delete_field
+      field_exists
+      field_equals
+    );
+}
 
 =head1 NAME
 
@@ -85,49 +92,35 @@ sub copy_field {
     if ( ! ( $record && $fromFieldName && $toFieldName ) ) { return; }
 
 
-    if ( not $fromSubfieldName or $fromSubfieldName eq ''
-      or not $toSubfieldName or $toSubfieldName eq ''
-    ) {
-        _copy_field({
-            record => $record,
-            from_field => $fromFieldName,
-            to_field => $toFieldName,
-            regex => $regex,
-            field_numbers => $field_numbers,
-        });
+    if (   not $fromSubfieldName
+        or $fromSubfieldName eq ''
+        or not $toSubfieldName
+        or $toSubfieldName eq '' ) {
+        _copy_move_field(
+            {   record        => $record,
+                from_field    => $fromFieldName,
+                to_field      => $toFieldName,
+                regex         => $regex,
+                field_numbers => $field_numbers,
+                action        => 'copy',
+            }
+        );
     } else {
-        _copy_subfield({
-            record => $record,
-            from_field => $fromFieldName,
-            from_subfield => $fromSubfieldName,
-            to_field => $toFieldName,
-            to_subfield => $toSubfieldName,
-            regex => $regex,
-            field_numbers => $field_numbers,
-        });
+        _copy_move_subfield(
+            {   record        => $record,
+                from_field    => $fromFieldName,
+                from_subfield => $fromSubfieldName,
+                to_field      => $toFieldName,
+                to_subfield   => $toSubfieldName,
+                regex         => $regex,
+                field_numbers => $field_numbers,
+                action        => 'copy',
+            }
+        );
     }
-
 }
 
-sub _copy_field {
-    my ( $params ) = @_;
-    my $record = $params->{record};
-    my $fromFieldName = $params->{from_field};
-    my $toFieldName = $params->{to_field};
-    my $regex = $params->{regex};
-    my $field_numbers = $params->{field_numbers} // [];
-
-    _copy_move_field({
-        record => $record,
-        from_field => $fromFieldName,
-        to_field => $toFieldName,
-        regex => $regex,
-        field_numbers => $field_numbers,
-        action => 'copy',
-    });
-}
-
-sub _copy_subfield {
+sub copy_and_replace_field {
     my ( $params ) = @_;
     my $record = $params->{record};
     my $fromFieldName = $params->{from_field};
@@ -137,16 +130,34 @@ sub _copy_subfield {
     my $regex = $params->{regex};
     my $field_numbers = $params->{field_numbers} // [];
 
-    _copy_move_subfield({
-        record => $record,
-        from_field => $fromFieldName,
-        from_subfield => $fromSubfieldName,
-        to_field => $toFieldName,
-        to_subfield => $toSubfieldName,
-        regex => $regex,
-        field_numbers => $field_numbers,
-        action => 'copy',
-    });
+    if ( ! ( $record && $fromFieldName && $toFieldName ) ) { return; }
+
+
+    if ( !defined $fromSubfieldName or $fromSubfieldName eq ''
+      or !defined $toSubfieldName or $toSubfieldName eq ''
+    ) {
+        _copy_move_field(
+            {   record        => $record,
+                from_field    => $fromFieldName,
+                to_field      => $toFieldName,
+                regex         => $regex,
+                field_numbers => $field_numbers,
+                action        => 'replace',
+            }
+        );
+    } else {
+        _copy_move_subfield(
+            {   record        => $record,
+                from_field    => $fromFieldName,
+                from_subfield => $fromSubfieldName,
+                to_field      => $toFieldName,
+                to_subfield   => $toSubfieldName,
+                regex         => $regex,
+                field_numbers => $field_numbers,
+                action        => 'replace',
+            }
+        );
+    }
 }
 
 sub update_field {
@@ -159,7 +170,7 @@ sub update_field {
 
     if ( ! ( $record && $fieldName ) ) { return; }
 
-    if ( not $subfieldName or $subfieldName eq '' ) {
+    if ( not defined $subfieldName or $subfieldName eq '' ) {
         # FIXME I'm not sure the actual implementation is correct.
         die "This action is not implemented yet";
         #_update_field({ record => $record, field => $fieldName, values => \@values });
@@ -168,6 +179,45 @@ sub update_field {
     }
 }
 
+=head2 add_field
+
+  add_field({
+      record   => $record,
+      field    => $fieldName,
+      subfield => $subfieldName,
+      values   => \@values,
+      field_numbers => $field_numbers,
+  });
+
+  Adds a new field/subfield with supplied value(s).
+  This function always add a new field as opposed to 'update_field' which will
+  either update if field exists and add if it does not.
+
+=cut
+
+
+sub add_field {
+    my ( $params ) = @_;
+    my $record = $params->{record};
+    my $fieldName = $params->{field};
+    my $subfieldName = $params->{subfield};
+    my @values = @{ $params->{values} };
+    my $field_numbers = $params->{field_numbers} // [];
+
+    if ( ! ( $record && $fieldName ) ) { return; }
+    if ( $fieldName > 10 ) {
+        foreach my $value ( @values ) {
+            my $field = MARC::Field->new( $fieldName, '', '', "$subfieldName" => $value );
+            $record->append_fields( $field );
+        }
+    } else {
+        foreach my $value ( @values ) {
+            my $field = MARC::Field->new( $fieldName, $value );
+            $record->append_fields( $field );
+        }
+    }
+}
+
 sub _update_field {
     my ( $params ) = @_;
     my $record = $params->{record};
@@ -252,7 +302,7 @@ sub read_field {
     my $subfieldName = $params->{subfield};
     my $field_numbers = $params->{field_numbers} // [];
 
-    if ( not $subfieldName or $subfieldName eq '' ) {
+    if ( not defined $subfieldName or $subfieldName eq '' ) {
         _read_field({ record => $record, field => $fieldName, field_numbers => $field_numbers });
     } else {
         _read_subfield({ record => $record, field => $fieldName, subfield => $subfieldName, field_numbers => $field_numbers });
@@ -371,9 +421,15 @@ sub field_equals {
   my @field_numbers = ();
   my $current_field_number = 1;
   FIELDS: for my $field ( $record->field( $fieldName ) ) {
-    my @subfield_values = $subfieldName
-        ? $field->subfield( $subfieldName )
-        : map { $_->[1] } $field->subfields;
+    my @subfield_values;
+    if ( $field->is_control_field ) {
+        push @subfield_values, $field->data;
+    } else {
+        @subfield_values =
+            $subfieldName
+          ? $field->subfield($subfieldName)
+          : map { $_->[1] } $field->subfields;
+    }
 
     SUBFIELDS: for my $subfield_value ( @subfield_values ) {
       if (
@@ -416,69 +472,34 @@ sub move_field {
     my $regex = $params->{regex};
     my $field_numbers = $params->{field_numbers} // [];
 
-    if ( not $fromSubfieldName or $fromSubfieldName eq ''
-        or not $toSubfieldName or $toSubfieldName eq ''
-    ) {
-        _move_field({
-            record => $record,
-            from_field => $fromFieldName,
-            to_field => $toFieldName,
-            regex => $regex,
-            field_numbers => $field_numbers,
-        });
+    if (   !defined $fromSubfieldName
+        or $fromSubfieldName eq ''
+        or !defined $toSubfieldName
+        or $toSubfieldName eq '' ) {
+        _copy_move_field(
+            {   record        => $record,
+                from_field    => $fromFieldName,
+                to_field      => $toFieldName,
+                regex         => $regex,
+                field_numbers => $field_numbers,
+                action        => 'move',
+            }
+        );
     } else {
-        _move_subfield({
-            record => $record,
-            from_field => $fromFieldName,
-            from_subfield => $fromSubfieldName,
-            to_field => $toFieldName,
-            to_subfield => $toSubfieldName,
-            regex => $regex,
-            field_numbers => $field_numbers,
-        });
+        _copy_move_subfield(
+            {   record        => $record,
+                from_field    => $fromFieldName,
+                from_subfield => $fromSubfieldName,
+                to_field      => $toFieldName,
+                to_subfield   => $toSubfieldName,
+                regex         => $regex,
+                field_numbers => $field_numbers,
+                action        => 'move',
+            }
+        );
     }
 }
 
-sub _move_field {
-    my ( $params ) = @_;
-    my $record = $params->{record};
-    my $fromFieldName = $params->{from_field};
-    my $toFieldName = $params->{to_field};
-    my $regex = $params->{regex};
-    my $field_numbers = $params->{field_numbers} // [];
-
-    _copy_move_field({
-        record => $record,
-        from_field => $fromFieldName,
-        to_field => $toFieldName,
-        regex => $regex,
-        field_numbers => $field_numbers,
-        action => 'move',
-    });
-}
-
-sub _move_subfield {
-    my ( $params ) = @_;
-    my $record = $params->{record};
-    my $fromFieldName = $params->{from_field};
-    my $fromSubfieldName = $params->{from_subfield};
-    my $toFieldName = $params->{to_field};
-    my $toSubfieldName = $params->{to_subfield};
-    my $regex = $params->{regex};
-    my $field_numbers = $params->{field_numbers} // [];
-
-    _copy_move_subfield({
-        record => $record,
-        from_field => $fromFieldName,
-        from_subfield => $fromSubfieldName,
-        to_field => $toFieldName,
-        to_subfield => $toSubfieldName,
-        regex => $regex,
-        field_numbers => $field_numbers,
-        action => 'move',
-    });
-}
-
 =head2 _delete_field
 
   _delete_field( $record, $fieldName[, $subfieldName [, $n ] ] );
@@ -497,7 +518,7 @@ sub delete_field {
     my $subfieldName = $params->{subfield};
     my $field_numbers = $params->{field_numbers} // [];
 
-    if ( not $subfieldName or $subfieldName eq '' ) {
+    if ( !defined $subfieldName or $subfieldName eq '' ) {
         _delete_field({ record => $record, field => $fieldName, field_numbers => $field_numbers });
     } else {
         _delete_subfield({ record => $record, field => $fieldName, subfield => $subfieldName, field_numbers => $field_numbers });
@@ -535,6 +556,7 @@ sub _delete_subfield {
 
     foreach my $field ( @fields ) {
         $field->delete_subfield( code => $subfieldName );
+        $record->delete_field( $field ) unless $field->subfields();
     }
 }
 
@@ -548,13 +570,14 @@ sub _copy_move_field {
     my $field_numbers = $params->{field_numbers} // [];
     my $action = $params->{action} || 'copy';
 
-    my @fields = $record->field( $fromFieldName );
+    my @from_fields = $record->field( $fromFieldName );
     if ( @$field_numbers ) {
-        @fields = map { $_ <= @fields ? $fields[ $_ - 1 ] : () } @$field_numbers;
+        @from_fields = map { $_ <= @from_fields ? $from_fields[ $_ - 1 ] : () } @$field_numbers;
     }
 
-    for my $field ( @fields ) {
-        my $new_field = $field->clone;
+    my @new_fields;
+    for my $from_field ( @from_fields ) {
+        my $new_field = $from_field->clone;
         $new_field->{_tag} = $toFieldName; # Should be replaced by set_tag, introduced by MARC::Field 2.0.4
         if ( $regex and $regex->{search} ) {
             for my $subfield ( $new_field->subfields ) {
@@ -563,10 +586,18 @@ sub _copy_move_field {
                 $new_field->update( $subfield->[0], $value );
             }
         }
-        $record->append_fields( $new_field );
-        $record->delete_field( $field )
-            if $action eq 'move';
+        if ( $action eq 'move' ) {
+            $record->delete_field( $from_field )
+        }
+        elsif ( $action eq 'replace' ) {
+            my @to_fields = $record->field( $toFieldName );
+            if ( @to_fields ) {
+                $record->delete_field( $to_fields[0] );
+            }
+        }
+        push @new_fields, $new_field;
     }
+    $record->append_fields( @new_fields );
 }
 
 sub _copy_move_subfield {
@@ -605,6 +636,9 @@ sub _modify_values {
     my $regex = $params->{regex};
 
     if ( $regex and $regex->{search} ) {
+        my $replace = $regex->{replace};
+        $replace =~ s/"/\\"/g;                    # Protection from embedded code
+        $replace = '"' . $replace . '"'; # Put in a string for /ee
         $regex->{modifiers} //= q||;
         my @available_modifiers = qw( i g );
         my $modifiers = q||;
@@ -614,16 +648,16 @@ sub _modify_values {
         }
         foreach my $value ( @$values ) {
             if ( $modifiers =~ m/^(ig|gi)$/ ) {
-                $value =~ s/$regex->{search}/$regex->{replace}/ig;
+                $value =~ s/$regex->{search}/$replace/igee;
             }
             elsif ( $modifiers eq 'i' ) {
-                $value =~ s/$regex->{search}/$regex->{replace}/i;
+                $value =~ s/$regex->{search}/$replace/iee;
             }
             elsif ( $modifiers eq 'g' ) {
-                $value =~ s/$regex->{search}/$regex->{replace}/g;
+                $value =~ s/$regex->{search}/$replace/gee;
             }
             else {
-                $value =~ s/$regex->{search}/$regex->{replace}/;
+                $value =~ s/$regex->{search}/$replace/ee;
             }
         }
     }