[Catalyst] Sub-classing Application

J. Shirley jshirley at gmail.com
Wed Dec 16 17:59:11 GMT 2009


On Wed, Dec 16, 2009 at 9:27 AM, Bill Moseley <moseley at hank.org> wrote:
>
>
> On Wed, Dec 16, 2009 at 8:31 AM, J. Shirley <jshirley at gmail.com> wrote:
>>
>>
>> The documentation seems quite sparse, but if you look at the source it
>> just essentially does:
>>    my $locator = Module::Pluggable::Object->new(
>>        search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
>>        %$config
>>    );
>>
>> If you have MyApp->config->{search_extra} = [ 'Foo::Controller',
>> 'Foo::Model' ]; it should DTRT.
>
> It almost works, but it sets up actions for both controllers using each
> controller's class.
>
> That is, if I start application Bar and pass in search_extra => [qw/
> Foo::Controller / ] then indeed actions from Foo::Controller::* will get
> added to the application.
>
> But, they are added with the Foo:: namespace.  that is, that controller is
> not a parent-class of Bar::Controller::*.
>
> It also means I can't easly overide.  If I have hello() in both thes
> controllers:
>
> Foo::Controller::Whatever::hello()
> Bar::Controller::Whatever::hello()
>
> I then get:
>
> [debug] Loaded Path actions:
> .-------------------------------------+--------------------------------------.
> | Path                                | Private
> |
> +-------------------------------------+--------------------------------------+
> | /                                   | /index
> |
> | /                                   | /index
> |
> | /                                   | /default
> |
> | /                                   | /default
> |
> | /whatever/hello                     | /whatever/hello
> |
> | /whatever/hello                     | /whatever/hello
> |
> | /whatever/howdy                     | /whatever/howdy
> |
> '-------------------------------------+--------------------------------------'
>
> So, I guess what I really would like is a way to have it load the Foo::*
> modules but register their actions in the associated Bar:: namespace
> so that /whatever/hello calls Bar::Whatever::hello but Foo::Whatever is the
> parent class if hello() doesn't exist in Bar.
>
> (That sentense make sense?)
>
> I guess that means when Foo::Controller::Whatever is found, register the
> actions in the Bar::Whatever namespace and push Foo::Whatever onto
> @Bar::Whatever::ISA.
>
>
> The problem I'm looking at is rebranding applications.  In the past I've
> managed to modify config based on, say, domain name and use a different root
> (for templates, css, images, etc.)  But, over time the application has to be
> forked due to changes in code.  But, 90% of the controller code is still the
> same between the two applications.
>
> So, it would be handy to say, this application inheits from Foo, but these
> with a few methods added or overridden.
>
>

It seems you're after something that would best be accomplished using
roles that get composed into the controller.

http://search.cpan.org/~hkclark/Catalyst-Manual-5.8002/lib/Catalyst/Manual/CatalystAndMoose.pod#ROLES_AND_METHOD_MODIFIERS

I've done similar things (and maintain it) and the sections that I
refactored to use this method are much more maintainable (and using
Chained).  When I just mix random things or maintain a copy'n'paste
swath, bad things happen.

Probably not an ideal answer, but I actually found the refactoring was
pretty easy.

Essentially: cp Controller/Foo.pm MyApp/Role/Controller/Foo.pm then
converting it to use Moose::Role syntax per the CatalystAndMoose pod,
then modifying everything to just do 'with Controller::Foo';  It's
hard-coded still, and not ideal, but for me at least it is
write-once-forget-forever (and I see exactly what is composed into the
class, which makes debugging easier).

That's about the best I have for you, sorry :)

-J



More information about the Catalyst mailing list