
moseley at hank
Dec 31, 2011, 8:58 PM
Post #1 of 4
(239 views)
Permalink
|
|
Dynamic model and controller creation
|
|
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 => '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 => ( is => 'rw' ); # instance of model has service_class => ( is => 'ro', isa => 'Str', required => 1, ); # wrapping "setup_components" might be another approach sub ACCEPT_CONTEXT { my ( $self, $c, @args ) = @_; my $service = $self->service; unless ( $service ) { my $service_class = $self->service_class; Class::MOP::load_class( $service_class ); $service = $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 => '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
|