[Catalyst] Dynamic model and controller creation

Bill Moseley moseley at hank.org
Sun Jan 1 04:58:02 GMT 2012


I'm looking for examples of creating controllers and models via
configuration.  As I'm doing it now (below) I'm having to add a number of
pretty small classes that are almost entirely configuration.   It's pretty
simple as-is, but wondering if you might have a simpler approach (or doc
link) so that I can dynamically add actions and models either at runtime or
app config.


I have a very simple library I want provide a RESTful API for.  The library
has a base class, say Inventory::Service that provides a simple API with
CRUD-like metods add() and get().  This base class in not used directly,
rather subclasses exists. For example, Inventory::Service::Nut and
Inventory::Service::Bolt inherit from the base class.   There's potentially
a large number of these sub-classes.

So, I want a direct mapping "POST /service/bolt" to create and "GET
/service/bolt/<id>" to fetch the bolt, and likewise for the Nut and other
subclasses.

I've created a base class "MyApp::ControllerBase::Inventory" that has
generic methods thing_POST and thing_GET as per C::A::REST (that implement
the common ->add() and ->get() methods) and has an attribute "model_class".

Then I have Controller classes inheriting from this class that are simply
config setting the "model_class" attribute:

package MyApp::Controller::Service::Bolt;
use base 'MyApp::ControllerBase::Inventory;
__PACKAGE__->config(  model_class =3D> 'Inventory::Bolt',);
1;


Which means the base class just does $c->model( $self->model_class ) to get
at the Inventory::Bolt model.

Then, likewise, I have a Model base class that uses ACCEPT_CONTEXT to
return specific instances:

package MyApp::ModelBase::Inventory;
use Moose;
use namespace::autoclean;
extends 'Catalyst::Model';

has service =3D> ( is =3D> 'rw' );  # instance of model

has service_class =3D> (
    is =3D> 'ro',
    isa =3D> 'Str',
    required =3D> 1,
);


# wrapping "setup_components" might be another approach
sub ACCEPT_CONTEXT {
    my ( $self, $c, @args ) =3D @_;

    my $service =3D $self->service;

    unless ( $service ) {
        my $service_class =3D $self->service_class;
        Class::MOP::load_class( $service_class );

        $service =3D $service_class->new;

        # Save our instance
        $self->service( $service );
    }

    return $service;
}


__PACKAGE__->meta->make_immutable;
1;


And then the specific model classes are simply:

package MyApp::Model::Inventory::Bolt;
use base 'MyApp::ModelBase::Inventory';
__PACKAGE__->config( service_class =3D> 'Inventory::Service::Bolt' );
1;


Of course, after doing that a few times I'd rather use a programatic
solution.

So, what I'd like is to remove the need to create those stub Controller and
Model classes and instead use config (or maybe detection of available
subclasses at startup).


-- =

Bill Moseley
moseley at hank.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/catalyst/attachments/20120101/6ef84=
37f/attachment.htm


More information about the Catalyst mailing list