use Modern::Perl;
use Carp;
+use Mojo::JSON;
+use Try::Tiny;
use Koha::Database;
use Koha::Exceptions::Object;
+use Koha::DateUtils;
=head1 NAME
sub store {
my ($self) = @_;
- return $self->_result()->update_or_insert() ? $self : undef;
+ try {
+ return $self->_result()->update_or_insert() ? $self : undef;
+ }
+ catch {
+ # 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 \(`(?<column>.*?)`\)/ ) {
+ Koha::Exceptions::Object::FKConstraint->throw(
+ error => 'Broken FK constraint',
+ broken_fk => $+{column}
+ );
+ }
+ }
+ elsif( $_->{msg} =~ /Duplicate entry '(.*?)' for key '(?<key>.*?)'/ ) {
+ Koha::Exceptions::Object::DuplicateID->throw(
+ error => 'Duplicate ID',
+ duplicate_id => $+{key}
+ );
+ }
+ # Catch-all for foreign key breakages. It will help find other use cases
+ $->rethrow();
+ }
+ }
}
=head3 $object->delete();
sub delete {
my ($self) = @_;
- # Deleting something not in storage thows an exception
+ # Deleting something not in storage throws an exception
return -1 unless $self->_result()->in_storage();
# Return a boolean for succcess
return { $self->_result->get_columns };
}
+=head3 $object->TO_JSON
+
+Returns an unblessed representation of the object, suitable for JSON output.
+
+=cut
+
+sub TO_JSON {
+
+ my ($self) = @_;
+
+ my $unblessed = $self->unblessed;
+ my $columns_info = Koha::Database->new->schema->resultset( $self->_type )
+ ->result_source->{_columns};
+
+ foreach my $col ( keys %{$columns_info} ) {
+
+ if ( $columns_info->{$col}->{is_boolean} )
+ { # Handle booleans gracefully
+ $unblessed->{$col}
+ = ( $unblessed->{$col} )
+ ? Mojo::JSON->true
+ : Mojo::JSON->false;
+ }
+ elsif ( _numeric_column_type( $columns_info->{$col}->{data_type} ) ) {
+
+ # TODO: Remove once the solution for
+ # https://rt.cpan.org/Ticket/Display.html?id=119904
+ # is ported to whatever distro we support by that time
+ $unblessed->{$col} += 0;
+ }
+ elsif ( _datetime_column_type( $columns_info->{$col}->{data_type} ) ) {
+ eval {
+ return unless $unblessed->{$col};
+ $unblessed->{$col} = output_pref({
+ dateformat => 'rfc3339',
+ dt => dt_from_string($unblessed->{$col}, 'sql'),
+ });
+ };
+ }
+ }
+ return $unblessed;
+}
+
+sub _datetime_column_type {
+ my ($column_type) = @_;
+
+ my @dt_types = (
+ 'timestamp',
+ 'datetime'
+ );
+
+ return ( grep { $column_type eq $_ } @dt_types) ? 1 : 0;
+}
+
+sub _numeric_column_type {
+ # TODO: Remove once the solution for
+ # https://rt.cpan.org/Ticket/Display.html?id=119904
+ # is ported to whatever distro we support by that time
+ my ($column_type) = @_;
+
+ my @numeric_types = (
+ 'bigint',
+ 'integer',
+ 'int',
+ 'mediumint',
+ 'smallint',
+ 'tinyint',
+ 'decimal',
+ 'double precision',
+ 'float'
+ );
+
+ return ( grep { $column_type eq $_ } @numeric_types) ? 1 : 0;
+}
+
=head3 $object->_result();
Returns the internal DBIC Row object
return $self->{_columns};
}
-
=head3 AUTOLOAD
The autoload method is used only to get and set values for an objects properties.
}
}
- my @known_methods = qw( is_changed id in_storage get_column );
-
+ my @known_methods = qw( is_changed id in_storage get_column discard_changes update );
Koha::Exceptions::Object::MethodNotCoveredByTests->throw( "The method $method is not covered by tests!" ) unless grep {/^$method$/} @known_methods;
my $r = eval { $self->_result->$method(@_) };
if ( $@ ) {
- Koha::Exceptions::Object::MethodNotFound->throw( "No method $method for " . ref($self) );
+ Koha::Exceptions::Object->throw( ref($self) . "::$method generated this error: " . $@ );
}
return $r;
}