[Dbix-class] InflateColumn::DateTime, inheritance,
and insert/delete problems
Peter Rabbitson
rabbit+dbic at rabbit.us
Wed Mar 11 07:53:19 GMT 2009
Steve Caldwell wrote:
> Consider the following script:
>
> #!/usr/bin/perl
> use strict;
> use warnings;
>
> # mysql>
> # create database foo;
> # create table foo.tblfoo (
> # fooid integer not null auto_increment,
> # mydate datetime,
> # primary key (fooid)
> # );
> # grant all privileges on foo.* to foouser at localhost
> # identified by 'foopassword';
>
> use DateTime;
>
> {
> package My::Plugin::RowStuff;
> sub insert {
> my $self = shift;
> warn "I'm going to do something before inserting";
> $self->next::method(@_);
> }
> sub delete {
> my $self = shift;
> warn "I'm going to do something before deleting";
> $self->next::method(@_);
> }
> 1;
>
> package My::SchemaBase;
> use base 'DBIx::Class';
> __PACKAGE__->load_components(qw/
> InflateColumn::DateTime
> +My::Plugin::RowStuff
> Core
> /);
> 1;
>
> package My::Schema::Foo;
> use base 'My::SchemaBase';
> __PACKAGE__->table('tblfoo');
> __PACKAGE__->add_columns(
> fooid => {},
> mydate => { data_type => 'datetime' },
> );
> __PACKAGE__->set_primary_key('fooid');
> 1;
>
> package My::Schema;
> use base 'DBIx::Class::Schema';
> My::Schema->load_classes(qw/Foo/);
> 1;
> }
>
> my $schema = My::Schema->connect(
> 'DBI:mysql:database=foo', 'foouser', 'foopassword'
> );
>
> my $obj = $schema->resultset('Foo')->create({
> mydate => DateTime->now(),
> });
>
> $obj->delete();
>
> exit 0;
>
> 1;
>
>
> When I run this, my custom insert and delete methods in
> My::Plugin::RowStuff do not get run. I can't figure out why not, but I
> have identified the following:
>
> 1) removing InflateColumn::DateTime will make it work
>
> 2) removing the inheritance of My::SchemaBase will work - i.e. have
> My::Schema::Foo inherit directly from DBIx::Class and call
> load_components(...) in that package.
>
> 3) adding skeleton insert and delete methods to My::SchemaBase will
> work, so that it now looks like:
>
> package My::SchemaBase;
> use base 'DBIx::Class';
> __PACKAGE__->load_components(qw/
> InflateColumn::DateTime
> +My::Plugin::RowStuff
> Core
> /);
> sub insert { shift->next::method(@_) }
> sub delete { shift->next::method(@_) }
> 1;
>
> As #1 and #2 aren't viable for my codebase, I'm going with the odd #3
> solution. Does anyone know why InflateColumn::DateTime is exhibiting
> this behavior?
>
Sadly this is a weird MRO problem, and not really a DBIC issue. Consider:
#!/usr/bin/perl
use strict;
use warnings;
# Everything ultimately inherits from this
package RootPkg;
sub root {__PACKAGE__};
# Chain 1 - Extra -> Extra::Sub -> RootPkg
package Extra::Sub;
use base qw/Class::C3::Componentised/;
sub component_base_class { __PACKAGE__ };
__PACKAGE__->load_components qw/+RootPkg/;
package Extra;
use base qw/Class::C3::Componentised/;
sub component_base_class { __PACKAGE__ };
__PACKAGE__->load_components qw/Sub/;
#Chain2 - BasePkg --> BasePkg::Sub1 --> RootPkg
# \-> BasePkg::Sub2 -/
package BasePkg::Sub1;
use base qw/Class::C3::Componentised/;
sub component_base_class { __PACKAGE__ };
__PACKAGE__->load_components qw/+RootPkg/;
package BasePkg::Sub2;
use base qw/Class::C3::Componentised/;
sub component_base_class { __PACKAGE__ };
__PACKAGE__->load_components qw/+RootPkg/;
package BasePkg;
use base qw/Class::C3::Componentised/;
sub component_base_class { __PACKAGE__ };
__PACKAGE__->load_components qw/+Extra Sub1 Sub2/;
# Two end users
package User1;
use base qw/BasePkg/;
package User2;
use base qw/Class::C3::Componentised/;
sub component_base_class { __PACKAGE__ };
__PACKAGE__->load_components qw/+Extra +BasePkg::Sub1 +BasePkg::Sub2/;
package main;
use Data::Dumper;
use MRO::Compat;
# just to be sure
Class::C3::reinitialize();
$Data::Dumper::Sortkeys = 1;
print Dumper {
"MRO after User1 use base BasePkg (which load_components qw/+Extra Sub1 Sub2/)" => mro::get_linear_isa ('User1'),
'MRO after User2->load_components qw/+Extra +BasePkg::Sub1 +BasePkg::Sub2/' => mro::get_linear_isa ('User2'),
};
Which outputs:
$VAR1 = {
'MRO after User1 use base BasePkg (which load_components qw/+Extra Sub1 Sub2/)' => [
'User1',
'BasePkg',
'Extra',
'Extra::Sub',
'RootPkg',
'Class::C3::Componentised',
'BasePkg::Sub1',
'BasePkg::Sub2'
],
'MRO after User2->load_components qw/+Extra +BasePkg::Sub1 +BasePkg::Sub2/' => [
'User2',
'Extra',
'Extra::Sub',
'BasePkg::Sub1',
'BasePkg::Sub2',
'RootPkg',
'Class::C3::Componentised'
]
};
Your case is User1, where InflateColumn::DateTime == Extra, RootPkg == DBIx::Class::Row
(which implements the terminating insert() and delete() ) and and My::Plugin::RowStuff
== BasePkg::Sub1. The rest you can deduce yourself :)
More information about the DBIx-Class
mailing list