@@ -, +, @@ incorrect values --- Koha/Object.pm | 123 ++++++++++++++++++++++++++++++++++--------- t/db_dependent/Koha/Object.t | 3 ++ 2 files changed, 101 insertions(+), 25 deletions(-) --- a/Koha/Object.pm +++ a/Koha/Object.pm @@ -118,37 +118,110 @@ Returns: =cut -sub store { - my ($self) = @_; +sub _fix_default_value { + my ($self, $params) = @_; + + my $column_info = $params->{column_info}; + my $col = $params->{col}; + my $val = exists $params->{val} ? $params->{val} : $self->$col; + + return unless $column_info; # the column does not exist + + my $reset; + # Integers + if ( _numeric_column_type( $column_info->{data_type} ) ) { + # Has been passed but not a number, usually an empty string + if ( defined $val and not looks_like_number( $val ) ) { + if ( $column_info->{is_nullable} ) { + # If nullable, default to null + $val = undef; + $reset = 1; + } else { + # If cannot be null, get the default value + # What if cannot be null and does not have a default value? Possible? + $val = $column_info->{default_value}; + $reset = 1; + } + } + } + elsif ( _date_or_datetime_column_type( $column_info->{data_type} ) ) { + # Set to null if an empty string (or == 0 but should not happen) + if ( defined $val and not $val ) { + if ( $column_info->{is_nullable} ) { + $val = undef; + $reset = 1; + } else { + $val = $column_info->{default_value}; + $reset = 1; + } + } + } + $self->$col($val) if $reset; + return $reset; +} - my $columns_info = $self->_result->result_source->columns_info; +sub update { + my ($self, $values) = @_; - # 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}); + my $columns_info = $self->_result->result_source->columns_info; + my $new_values; + for my $col ( keys %$values ) { + if ( + $self->_fix_default_value( + { + col => $col, + column_info => $columns_info->{$col}, + val => $values->{$col} } - } + ) + ) + { + $values->{$col} = $self->$col; } - elsif ( _date_or_datetime_column_type( $columns_info->{$col}->{data_type} ) ) { - # Set to null if an empty string (or == 0 but should not happen) - if ( defined $self->$col and not $self->$col ) { - if ( $columns_info->{$col}->{is_nullable} ) { - $self->$col(undef); - } else { - $self->$col($columns_info->{$col}->{default_value}); + } + try { + return $self->_result->update($values) ? $self : undef; + } + catch { + # FIXME this is copied from ->store + + # Catch problems and raise relevant exceptions + if (ref($_) eq 'DBIx::Class::Exception') { + if ( $_->{msg} =~ /Cannot add or update a child row: a foreign key constraint fails/ ) { + # FK constraints + # FIXME: MySQL error, if we support more DB engines we should implement this for each + if ( $_->{msg} =~ /FOREIGN KEY \(`(?.*?)`\)/ ) { + Koha::Exceptions::Object::FKConstraint->throw( + error => 'Broken FK constraint', + broken_fk => $+{column} + ); } } + elsif( $_->{msg} =~ /Duplicate entry '(.*?)' for key '(?.*?)'/ ) { + Koha::Exceptions::Object::DuplicateID->throw( + error => 'Duplicate ID', + duplicate_id => $+{key} + ); + } + elsif( $_->{msg} =~ /Incorrect (?\w+) value: '(?.*)' for column '(?\w+)'/ ) { + Koha::Exceptions::Object::BadValue->throw( + type => $+{type}, + value => $+{value}, + property => $+{property} + ); + } } + Koha::Exceptions::Object->throw( ref($self) . "::update generated this error: " . $@ ); + } +} + +sub store { + my ($self) = @_; + + my $columns_info = $self->_result->result_source->columns_info; + # Handle not null and default values for integers and dates + foreach my $col ( keys %{$columns_info} ) { + $self->_fix_default_value({ col => $col, column_info => $columns_info->{$col} }); } try { @@ -452,7 +525,7 @@ sub AUTOLOAD { } } - my @known_methods = qw( is_changed id in_storage get_column discard_changes update make_column_dirty ); + my @known_methods = qw( is_changed id in_storage get_column discard_changes make_column_dirty ); Koha::Exceptions::Object::MethodNotCoveredByTests->throw( error => sprintf("The method %s->%s is not covered by tests!", ref($self), $method), --- a/t/db_dependent/Koha/Object.t +++ a/t/db_dependent/Koha/Object.t @@ -345,6 +345,9 @@ subtest 'store() tests' => sub { is( $itemtype->notforloan, undef, 'int DEFAULT NULL should default to null'); is( $itemtype->hideinopac, 0, 'int NOT NULL DEFAULT 0 should default to 0'); + $itemtype = $builder->build_object( { class => 'Koha::ItemTypes' }); + $itemtype->update({ notforloan => "" }); + subtest 'Bad value tests' => sub { plan tests => 1; --