Problem with before_create triggers & objects

[prev] [thread] [next] [Date index for 2004/12/21]

From: Drew Taylor
Subject: Problem with before_create triggers & objects
Date: 18:24 on 21 Dec 2004
I've finally (Woo Hoo!) tracked down a problem (version 0.95, but also
present in earlier versions) I've been having with a before_create
trigger which autofills a "created" column. I am doing the following:

1) defining a "created" column 
2) setting up a has_a relationship for the "created" column using my
date class (which defines a deflate() method for getting mysql
datetime format, but stringifies via overloading to "MM/DD/YYYY
HH:MM"),
3) adding a before_create trigger to autopopulate the value

package Foo;
Foo->columns(All=>qw(id foo bar created updated));
Foo->has_a('created' => 'My::DateTime::Class');
Foo->add_trigger('before_create', \&_fill_created);

sub _fill_created {
    my $self = shift;
     my $date = My::DateTime::Class->now;#->deflate;
#    $self->_attribute_set('created', $date);
    $self->set('created', $date);
}

The problem is that when I call create() and the before_create
triggers are run I end up with 3 triggers: _deflate_object() as set
via has_a(), something via an overload call in CDBI, and my
_fill_created(), usually in that order.

In _deflate_object(), it calls $self->_attribute_exists($col) which
returns false because my trigger code has not run yet. This is the
gate keeper to _deflated_column() which does the actual object
deflation. Then later when my trigger does run it creates the object
and sets created, but it is not properly deflated because
_deflate_object() has already run!

So that's the problem in a nutshell. I have a workaround as seen in
the commented code above: use the low level accessors & set the final
value directly, which Just Works. But the problem I described above
was a serious bear to track down. It only manifested itself by
_usually_ (and not always!) having a blank created column value. I
guess it sometimes worked because perl gave CDBI the triggers in a
different order.

I don't know that there is any way to not force the use of the low
level accessors unless the order of triggers can be set. That would be
nice because any user level code could by default be set to run before
any of CDBI's built in triggers.

The simple fix seems to be to document that if you want to set column
values via a before_create trigger you MUST ALWAYS use the
_attribute_* methods.

Drew
        -- 
        ----------------------------------------------------------------
 Drew Taylor                 *  Web development & consulting
 Email: drew@xxxxxxxxxx.xxx  *  Site implementation & hosting
 Web  : www.drewtaylor.com   *  perl/mod_perl/DBI/mysql/postgres
 ----------------------------------------------------------------

Problem with before_create triggers & objects
Drew Taylor 18:24 on 21 Dec 2004

Re: Problem with before_create triggers & objects
Charles Bailey 18:42 on 21 Dec 2004

Generated at 12:15 on 16 Jan 2005 by mariachi v0.52