[Catalyst] Base controllers and multiple inheritance

Byron Young Byron.Young at riverbed.com
Wed Mar 5 22:29:30 GMT 2008


Byron Young wrote:
> Hi,
> 
> I've been using Catalyst for a project and decided to make some base
> controllers for common functionality.  So far I've made two: CRUD, and
> List, for standard database operations and for sortable, paged
> listings 
> of data.  They work fine on their own but I'm running into trouble
> with multiple inheritance.  If I have a controller for some database
> table 
> that I want to inherit the actions from both CRUD and List, only the
> first one inherited will initialize properly.
> 
> The inheritance looks like this:
> 
>                    Catalyst::Controller
>                         /        \
>                        /          \
>                       /            \
>                      /            Catalyst::Controller::HTML::FormFu
>                     /               |
> MyApp::Base::Controller::List       |
>                     \               |
>                      \            MyApp::Base::Controller::CRUD
>                       \            /
>                        \          /
>                         \        /
>                MyApp::Controller::SomeDatabaseTable
> 
> 
> Each of the controller base classes has a new() method which sets up
> config data and does error checking and whatnot.  If I inherit both of
> my base classes, only new() on the first inherited is called.  I've
> tried calling $class->NEXT::new(@_) in each, and I've also tried
> Class::C3's $class->maybe::next::method(@_), but new() is still not
> called down the second inheritance chain.  When I tried the Class::C3
> approach I called Class::C3::initialize() in MyApp.pm - I wasn't sure
> where to call it so I tried before and after MyApp->setup() - still no
> luck.
> 
> Can somebody tell me why new() isn't called down both paths?
> 

Sorry for the pestering, but allow me to provide some more info.  I was
hoping to have my controllers inherit a number of base controllers that
I've got planned, but maybe I'm taking the wrong approach?  Seems like
this is probably a pretty common thing, but I haven't found anything
about it in the email list backlogs or anywhere else, except a comment
from jrockaway saying that you can inherit multiple base classes.

Here are my new() methods in the various classes:

---
package MyApp::Controller::SomeController;
use base qw/
            MyApp::Base::Controller::CRUD
            MyApp::Base::Controller::List
           /;

use Class::C3;

sub new {
    my $class = shift;
    my ($c) = @_;
    my $self = $class->maybe::next::method(@_);

    $c->log->debug("in SomeController::new");

    return $self;
}


---
package MyApp::Base::Controller::List;
use base qw( Catalyst::Controller Class::Accessor::Fast );

use Class::C3;

__PACKAGE__->mk_accessors(qw( _list_config ));

sub new {
    my $class = shift;
    my ($c) = @_;
    my $self = $class->maybe::next::method(@_);
    
    $c->log->debug("in List::new");

    $self->_list_setup( $c );

    return $self;
}

---
package MyApp::Base::Controller::CRUD;
use base qw( Catalyst::Controller::HTML::FormFu );

use Class::C3;

__PACKAGE__->mk_accessors(qw( _crud_config ));

sub new {
    my $class = shift;
    my ($c) = @_;
    my $self = $class->maybe::next::method(@_);
    
    $c->log->debug("in CRUD::new");

    $self->_crud_setup( $c );

    return $self;
}



I also added a $c->log->debug("in FormFu::new") in
Catalyst::Controller::HTML::FormFu::new().  Here's the output:

[debug] in FormFu::new
[debug] in CRUD::new
[debug] in CRUD::_crud_setup
[debug] in SomeController::new

List's new() is not called in that case.

Here's what happens when I inherit List before CRUD in SomeController:

[debug] in FormFu::new
[debug] in CRUD::new
[debug] in CRUD::_crud_setup
[debug] in List::new
[debug] in List::_list_setup
[debug] in TestModule::new

Everything looks good, right?  My List actions work!  However, the CRUD
actions don't work because the FormConfig actions seem to have been
ignored -- $c->stash->{form} is undef :(

Does anyone have any suggestions?  Should I just forego using new() and
do initial setup the first time auto() is called in each of my base
controllers?

Thanks,
Byron



More information about the Catalyst mailing list