View | Details | Raw Unified | Return to bug 19871
Collapse All | Expand All

(-)a/Koha/Object.pm (-18 / +3 lines)
Lines 174-199 sub store { Link Here
174
        return $self->_result()->update_or_insert() ? $self : undef;
174
        return $self->_result()->update_or_insert() ? $self : undef;
175
    } catch {
175
    } catch {
176
176
177
        # Use centralized exception translation
177
        # Log DBIx::Class exceptions for debugging (expected by tests)
178
        warn $_->{msg} if ref($_) eq 'DBIx::Class::Exception';
178
        warn $_->{msg} if ref($_) eq 'DBIx::Class::Exception';
179
179
180
        # For enum data truncation, we need to pass the object value which the utility can't access
180
        # Delegate to centralized exception translation with object context for enum handling
181
        if ( ref($_) eq 'DBIx::Class::Exception' && $_->{msg} =~ /Data truncated for column \W?(?<property>\w+)/ ) {
181
        $self->_result->result_source->schema->translate_exception( $_, $columns_info, $self );
182
            my $property = $+{property};
183
            my $type     = $columns_info->{$property}->{data_type} // '';
184
            if ( $type eq 'enum' ) {
185
                Koha::Exceptions::Object::BadValue->throw(
186
                    type     => 'enum',
187
                    property => $property =~ /(\w+\.\w+)$/
188
                    ? $1
189
                    : $property,    # results in table.column without quotes or backticks
190
                    value => $self->$property,
191
                );
192
            }
193
        }
194
195
        # Delegate to centralized exception translation
196
        $self->_result->result_source->schema->translate_exception( $_, $columns_info );
197
    }
182
    }
198
}
183
}
199
184
(-)a/Koha/Schema.pm (-4 / +4 lines)
Lines 56-67 This provides a centralized way to handle database exceptions throughout the app Link Here
56
=cut
56
=cut
57
57
58
sub safe_do {
58
sub safe_do {
59
    my ( $self, $code_ref, $columns_info ) = @_;
59
    my ( $self, $code_ref, $columns_info, $object ) = @_;
60
60
61
    try {
61
    try {
62
        return $code_ref->();
62
        return $code_ref->();
63
    } catch {
63
    } catch {
64
        Koha::Schema::Util::ExceptionTranslator->translate_exception($_, $columns_info);
64
        Koha::Schema::Util::ExceptionTranslator->translate_exception($_, $columns_info, $object);
65
    };
65
    };
66
}
66
}
67
67
Lines 75-82 This allows the schema to act as a central point for exception handling. Link Here
75
=cut
75
=cut
76
76
77
sub translate_exception {
77
sub translate_exception {
78
    my ( $self, $exception, $columns_info ) = @_;
78
    my ( $self, $exception, $columns_info, $object ) = @_;
79
    return Koha::Schema::Util::ExceptionTranslator->translate_exception($exception, $columns_info);
79
    return Koha::Schema::Util::ExceptionTranslator->translate_exception($exception, $columns_info, $object);
80
}
80
}
81
81
82
# You can replace this text with custom content, and it will be preserved on regeneration
82
# You can replace this text with custom content, and it will be preserved on regeneration
(-)a/Koha/Schema/Util/ExceptionTranslator.pm (-3 / +10 lines)
Lines 80-86 If the exception cannot be translated, it rethrows the original exception. Link Here
80
=cut
80
=cut
81
81
82
sub translate_exception {
82
sub translate_exception {
83
    my ( $class, $exception, $columns_info ) = @_;
83
    my ( $class, $exception, $columns_info, $object ) = @_;
84
84
85
    # Only handle DBIx::Class exceptions
85
    # Only handle DBIx::Class exceptions
86
    return $exception->rethrow() unless ref($exception) eq 'DBIx::Class::Exception';
86
    return $exception->rethrow() unless ref($exception) eq 'DBIx::Class::Exception';
Lines 148-159 sub translate_exception { Link Here
148
        if ( $columns_info && $columns_info->{$property} ) {
148
        if ( $columns_info && $columns_info->{$property} ) {
149
            my $type = $columns_info->{$property}->{data_type};
149
            my $type = $columns_info->{$property}->{data_type};
150
            if ( $type && $type eq 'enum' ) {
150
            if ( $type && $type eq 'enum' ) {
151
                my $value = 'Invalid enum value';    # Default value
152
153
                # If we have an object, try to get the actual property value
154
                if ( $object && $object->can($property) ) {
155
                    eval { $value = $object->$property; };
156
                }
157
151
                Koha::Exceptions::Object::BadValue->throw(
158
                Koha::Exceptions::Object::BadValue->throw(
152
                    type     => 'enum',
159
                    type     => 'enum',
153
                    property => $property =~ /(\w+\.\w+)$/
160
                    property => $property =~ /(\w+\.\w+)$/
154
                    ? $1
161
                    ? $1
155
                    : $property,                      # results in table.column without quotes or backticks
162
                    : $property,    # results in table.column without quotes or backticks
156
                    value => 'Invalid enum value',    # We don't have access to the object here
163
                    value => $value,
157
                );
164
                );
158
            }
165
            }
159
        }
166
        }
(-)a/t/db_dependent/Koha/Schema/Util/ExceptionTranslator.t (-2 / +40 lines)
Lines 19-25 Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
use Test::NoWarnings;
21
use Test::NoWarnings;
22
use Test::More tests => 8;
22
use Test::More tests => 9;
23
use Test::Exception;
23
use Test::Exception;
24
24
25
use Koha::Database;
25
use Koha::Database;
Lines 144-149 subtest 'fk_constraint_deletion_translation' => sub { Link Here
144
    $schema->storage->txn_rollback;
144
    $schema->storage->txn_rollback;
145
};
145
};
146
146
147
subtest 'enum_truncation_with_object_value' => sub {
148
    plan tests => 2;
149
150
    $schema->storage->txn_begin;
151
152
    # Create a mock object with a property accessor
153
    my $mock_object = bless { test_enum => 'invalid_value' }, 'TestObject';
154
155
    # Add the can method to simulate a real object
156
    {
157
        no strict 'refs';
158
        *{"TestObject::can"} = sub {
159
            my ( $self, $method ) = @_;
160
            return $method eq 'test_enum' ? sub { return $self->{test_enum} } : undef;
161
        };
162
        *{"TestObject::test_enum"} = sub { return $_[0]->{test_enum} };
163
    }
164
165
    # Create a mock DBIx::Class::Exception for enum data truncation
166
    my $exception = bless { msg => "Data truncated for column 'test_enum'" }, 'DBIx::Class::Exception';
167
168
    # Mock column info with enum type
169
    my $columns_info = { test_enum => { data_type => 'enum' } };
170
171
    # Test with object - should include the actual value
172
    throws_ok {
173
        Koha::Schema::Util::ExceptionTranslator->translate_exception( $exception, $columns_info, $mock_object );
174
    }
175
    'Koha::Exceptions::Object::BadValue', 'Enum truncation with object throws BadValue exception';
176
177
    # Test without object - should use default value
178
    throws_ok {
179
        Koha::Schema::Util::ExceptionTranslator->translate_exception( $exception, $columns_info );
180
    }
181
    'Koha::Exceptions::Object::BadValue', 'Enum truncation without object throws BadValue exception';
182
183
    $schema->storage->txn_rollback;
184
};
185
147
subtest 'schema_safe_do_method' => sub {
186
subtest 'schema_safe_do_method' => sub {
148
    plan tests => 2;
187
    plan tests => 2;
149
188
150
- 

Return to bug 19871