Re: Better handling of constraint failures?
[prev]
[thread]
[next]
[Date index for 2004/08/12]
--=-aGovAYBNOr+jCG92j7+q
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Folks,
Here's the solution I came up with: Is this something that can make it
into Class::DBI proper?
I overrode add_constraint() in my Class::DBI subclass and have it now
return more useful information into %info in _croak().
sub add_constraint {
my $class = shift;
$class->_invalid_object_method('add_constraint()') if ref $class;
my $name = shift or return $class->_croak("Constraint needs a
name");
my $column = $class->find_column(+shift)
or return $class->_croak("Constraint $name needs a valid column");
my $code = shift
or return $class->_croak("Constraint $name needs a code
reference");
return $class->_croak("Constraint $name '$code' is not a code
reference")
unless ref($code) eq "CODE";
$column->is_constrained(1);
$class->add_trigger(
"before_set_$column" => sub {
my ($self, $value, $column_values) = @_;
$code->($value, $self, $column, $column_values)
or return $self->_croak(
"$class $column fails '$name' constraint with '$value'"
, #new
( #new
exception_type=>'constraint_failure', #new
column=>$column, #new
value=>$value, #new
constraint_name=>$name #new
) #new
);
}
);
}
I then catch that information in my overridden croak():
################################################################################
sub _croak {
my ($self, $message, %info) = @_;
Carp::croak(@_) if(not %info);
if ($info{exception_type} eq 'constraint_failure') {
$self->{__constraint_errors}->{$info{column}}=\%info;
} else {
Carp::croak(@_);
}
}
########################################
And then I use it in my scripts like this:
$namespace->namespace($new_value);
$namespace->description($new_description);
my $errors=$object->{__constraint_errors};
if(not %$errors){
$namespace->update();
}
and then I pass $errors to my form creating subroutine to output errors
for specific fields if they exist.
This minor tweak allows you to catch constraint errors and then
re-present a form to a user WITHOUT having to code my validation
routines in two different places.
The sketchy bit is putting info into the $object hash directly. . .
I think it should be expected that folks override _croak(), but
overriding add_constraint is a bit more troubling.
Fortunately, this shouldn't have a big impact on folks programming with
Class::DBI because I'm just populating %info with some meaningful stuff.
If you don't override _croak(), stuff will croak() per the usual.
The parts I changed in add_constraint() are marked with "#new" at the
end. I can give you a diff, if you want it.
Thoughts? I think more informational exceptions would generally be a
nice feature.
-DJCP
--
Dan Collis Puro
Chief Engineer
GeekUprising Internet Consultants
http://www.geekuprising.com
dan@xxxxxxxxxxxx.xxx
781-775-3942
--=-aGovAYBNOr+jCG92j7+q
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
<META NAME="GENERATOR" CONTENT="GtkHTML/3.0.10">
</HEAD>
<BODY>
Folks,<BR>
<BR>
Here's the solution I came up with: Is this something that can make it into Class::DBI proper?<BR>
<BR>
I overrode add_constraint() in my Class::DBI subclass and have it now return more useful information into %info in _croak().<BR>
<BR>
sub add_constraint {<BR>
my $class = shift;<BR>
$class->_invalid_object_method('add_constraint()') if ref $class;<BR>
my $name = shift or return $class->_croak("Constraint needs a name");<BR>
my $column = $class->find_column(+shift)<BR>
or return $class->_croak("Constraint $name needs a valid column");<BR>
my $code = shift<BR>
or return $class->_croak("Constraint $name needs a code reference");<BR>
return $class->_croak("Constraint $name '$code' is not a code reference")<BR>
unless ref($code) eq "CODE";<BR>
<BR>
$column->is_constrained(1);<BR>
$class->add_trigger(<BR>
"before_set_$column" => sub {<BR>
my ($self, $value, $column_values) = @_;<BR>
$code->($value, $self, $column, $column_values)<BR>
or return $self->_croak(<BR>
"$class $column fails '$name' constraint with '$value'"<BR>
, #new<BR>
( #new<BR>
exception_type=>'constraint_failure', #new<BR>
column=>$column, #new<BR>
value=>$value, #new<BR>
constraint_name=>$name #new<BR>
) #new<BR>
);<BR>
}<BR>
);<BR>
}<BR>
<BR>
I then catch that information in my overridden croak():<BR>
<BR>
<BR>
################################################################################<BR>
sub _croak {<BR>
my ($self, $message, %info) = @_;<BR>
Carp::croak(@_) if(not %info);<BR>
if ($info{exception_type} eq 'constraint_failure') {<BR>
$self->{__constraint_errors}->{$info{column}}=\%info;<BR>
} else {<BR>
Carp::croak(@_);<BR>
}<BR>
}<BR>
########################################<BR>
<BR>
<BR>
And then I use it in my scripts like this:<BR>
<BR>
$namespace->namespace($new_value);<BR>
$namespace->description($new_description);<BR>
<BR>
my $errors=$object->{__constraint_errors};<BR>
if(not %$errors){<BR>
$namespace->update();<BR>
}<BR>
<BR>
and then I pass $errors to my form creating subroutine to output errors for specific fields if they exist.<BR>
<BR>
This minor tweak allows you to catch constraint errors and then re-present a form to a user WITHOUT having to code my validation routines in two different places.<BR>
<BR>
The sketchy bit is putting info into the $object hash directly. . .<BR>
<BR>
I think it should be expected that folks override _croak(), but overriding add_constraint is a bit more troubling. <BR>
<BR>
Fortunately, this shouldn't have a big impact on folks programming with Class::DBI because I'm just populating %info with some meaningful stuff. If you don't override _croak(), stuff will croak() per the usual. <BR>
<BR>
The parts I changed in add_constraint() are marked with "#new" at the end. I can give you a diff, if you want it.<BR>
<BR>
Thoughts? I think more informational exceptions would generally be a nice feature.<BR>
<BR>
-DJCP<BR>
<BR>
<BR>
<PRE><TABLE CELLSPACING="0" CELLPADDING="0" WIDTH="100%">
<TR>
</TR>
<TR>
</TR>
<TR>
<TD>
<BR>
<PRE>--
Dan Collis Puro
Chief Engineer
GeekUprising Internet Consultants
http://www.geekuprising.com
dan@xxxxxxxxxxxx.xxx
781-775-3942</PRE>
</TD>
</TR>
</TABLE>
</PRE>
</BODY>
</HTML>
--=-aGovAYBNOr+jCG92j7+q--
|
|
Re: Better handling of constraint failures?
Daniel Collis Puro 20:01 on 12 Aug 2004
|