Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
93 lines (72 sloc) 3.98 KB
TODO, or the plan for making this stuff work right.
The goals:
1/ I want to be able to specify a Controller base class, like
Catalyst::Controller::MessageDriven. That's where my
message-handling actually lives, so I want to build controllers
based on that, or whichever other class.
2/ We need a calling convention for the model implementations - in the
absence of defined interfaces this should be simple unblessed data,
but if we do have an interface, we should be able to put proper
constraints on it.
3/ Given generated controllers where I expose a bunch of methods from
the actual model classes, there needs to be some way to control
which methods are dispatchable - "very public", if you like.
4/ I'd like to be able to write down an "interface", consisting of a
set of messages my app is willing to handle, and have the framework
(or the controller base class, probably) reject messages that
aren't in that set.
5/ I'd also like to be able to say in that interface definition what
types of object those methods expect as a payload.
6/ It'd be nice if exceptions from model methods were caught by the
framework and converted into messages representing the error -
i.e. to set an error status, and return the text of the exception.
All these things should be based on configuration. So, we've got
something to say what classes expose methods, which of those methods
are dispatchable, and which types are expected.
Possible Implementation
We can provide a number of controller base roles, for a number of
different message styles: YAML with type-tags, JSON bare hashes,
etc. # FIXME - how does this work with role merging when you want to override the default?
# maybe base class knows how to serialize generically, and loads a serialization engine...
# or should we have serialization model.. Hmm, more thought needed.
We then provide strategy classes for a number of
policies for what models, and which methods on those models
get reflected / are dispatchable etc..
FIXME - Models, or just the methods, I'm thinking the strategy
just works out which methods.
These should be selectable by configuration, the default
controller class plus overrides for specific controllers.
This makes the model to controller reflector config look like this:
__PACKAGE__->config(
'CatalystX::DynamicComponent::ModelToControllerReflector' => {
strategy => {
name => 'InterfaceRole',
roles => [qw/ My::Model::Interface::Role /],
},
include => '(Datacash|Cybersource|Paypal)^', # Reflect these models.
controller_superclasses => [qw/ Catalyst::Controller /], # Default, you can omit this line
controller_roles => [qw/ My::ControllerRole /],
},
'Controller::Paypal' => {
superclasses => [qw/ My::Other::SuperClass /], # _replaces_ classes set above
roles => [qw/ My::Other::ControllerRole /], # merged with role set above
},
);
The calling convention to model methods should be the "payload". That
might be a bare hashref for simple messages, or a blessed object of
some app-specific type if the message format contains first-class
objects, like tagged YAML.
The "interfaces" should be Roles, which don't provide any methods but
which "need" methods to be implemented. We then use the "needed"
methods as the set of dispatchable methods, given if we compile OK, we
know that the model class has all the required methods.
*** Do we require that the model class in question has already composed
the appropriate role, and just check that by introspection or do we just
add it ourselves? Adding it ourselves involves making an anon subclass
to avoid action at a distance, so the former if possibly preferable?
Types are implemented as type signatures on role methods, and we copy
them onto the actual methods on the model class at compile time.
**** I'm thinking this happens at role composition time..
Exception handling probably needs to be behaviour from the controller
base class, so that it can be specific to the type of message
serialization being used.