Bug 21610: Fix integers and dates values at Koha::Object->store level
authorJonathan Druart <jonathan.druart@bugs.koha-community.org>
Thu, 18 Oct 2018 21:55:44 +0000 (18:55 -0300)
committerroot <root@665746303f3b>
Fri, 1 Feb 2019 20:19:54 +0000 (20:19 +0000)
With strict SQL modes, we are facing several issues when objects are stored.

The following errors can be raised by DBIx::Class when an object does not have
a valid (as defined at DB level) value:
- Incorrect integer value: '' for column COLUMN
- Incorrect decimal value: '' for column COLUMN
- Column 'COLUMN' cannot be null
- Field 'COLUMN' doesn't have a default value
- Incorrect date value: '' for column 'COLUMN'

We already handled some of them for Koha::Patron. As we do not want to provide such
changes for all Koha::* modules we are going to fix this at Koha::Object->store level
in order to provide a global fix.

This is related to bug 21599 (for item types) and bug 21596 (for patrons)

Test plan:
- Apply first patch, run the tests
=> Patch fail because of the previous error in Koha::ItemType->store, to make them pass
you can replace
  $self->notforloan(0) unless $self->notforloan;
with
  $self->notforloan(undef) unless $self->notforloan;
- Apply second patch, run the tests
=> They fail because of dates and/or integers values
- Apply third patch, run the tests
=> They now pass

Deep code review wanted!

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Koha/Object.pm

index 98867d2..65790eb 100644 (file)
@@ -121,6 +121,31 @@ Returns:
 sub store {
     my ($self) = @_;
 
+    my $columns_info = Koha::Database->new->schema->resultset( $self->_type )
+        ->result_source->{_columns};
+
+    # Handle not null and default values for integers and dates
+    foreach my $col ( keys %{$columns_info} ) {
+        # Integers
+        if ( _numeric_column_type( $columns_info->{$col}->{data_type} ) ) {
+            # Has been passed but not a number, usually an empty string
+            if ( defined $self->$col and not looks_like_number( $self->$col ) ) {
+                if ( $columns_info->{$col}->{is_nullable} ) {
+                    # If nullable, default to null
+                    $self->$col(undef);
+                } else {
+                    # If cannot be null, get the default value
+                    # What if cannot be null and does not have a default value? Possible?
+                    $self->$col($columns_info->{$col}->{default_value});
+                }
+            }
+        }
+        elsif ( _date_or_datetime_column_type( $columns_info->{$col}->{data_type} ) ) {
+            # Set to null if an empty string (or == 0 but should not happen)
+            $self->$col(undef) unless $self->$col;
+        }
+    }
+
     try {
         return $self->_result()->update_or_insert() ? $self : undef;
     }
@@ -282,6 +307,17 @@ sub TO_JSON {
     return $unblessed;
 }
 
+sub _date_or_datetime_column_type {
+    my ($column_type) = @_;
+
+    my @dt_types = (
+        'timestamp',
+        'date',
+        'datetime'
+    );
+
+    return ( grep { $column_type eq $_ } @dt_types) ? 1 : 0;
+}
 sub _datetime_column_type {
     my ($column_type) = @_;