Add code from gists 12311[56]
[catagits/CatalystX-DynamicComponent.git] / t / lib / TestComplexApp / Controller / PaymentProvider.pm
CommitLineData
d4db6430 1package TestComplexApp::Controller::PaymentProvider;
2use Moose;
3use Moose::Meta::Class;
4use namespace::autoclean;
5
6BEGIN { extends 'Catalyst::Controller'; };
7
8=head1 NAME
9
10PaymentApp::Controller::PaymentProvider - Provider Controller factory
11
12=head1 DESCRIPTION
13
14This module creates dynamic Catalyst controllers based on
15configuration. It's intended for use with Catalyst::Engine::Stomp,
16where each controller namespace corresponds to a message queue
17subscription.
18
19The generated controllers expect Model classes to be defined for the
20configured payment providers, as configured by
21PaymentApp::Model::PaymentProvider - and in fact we borrow that
22module's config.
23
24We create one controller for each configured payment provider, for
25each configured environment. The generated namespace is based on both
26these names, so you end up with queues like "live_datacash".
27
28The relevant configuration comes from Catalyst, and should resemble
29this:
30
31 Model::PaymentProvider:
32 providers:
33 - PaymentProvider::Datacash
34 - PaymentProvider::Cybersource
35 - PaymentProvider::Null
36
37 Controller::PaymentProvider:
38 environments:
39 - qa
40 - test
41 - custqa
42 - uat
43
44=head1 TODO
45
46We're currently hardcoding the list of methods which form the
47interface to a payment processor. This will change - we will require
48that a payment provider class "does" a Moose role, and that role will
49indicate the methods we should consider dispatchable.
50
51=head1 SEE ALSO
52
53PaymentApp::Model::PaymentProvider - this module's partner in crime.
54
55=cut
56
57__PACKAGE__->config( namespace => '' );
58
59sub COMPONENT {
60 my $self = shift->next::method(@_);
61
62 # Sneakily borrow our corresponding model's config for providers
63 my $model_config = $self->_app->config->{'Model::PaymentProvider'};
64 my $provider_classes = $model_config->{providers};
65
66 # Environment list is from our own config.
67 my $environments = $self->{environments};
68
69 # For each configured provider/environment combination, create
70 # a Controller class which dispatches a set of methods to the
71 # provider's Model.
72 for my $provider_class (@$provider_classes) {
73 for my $environment (@$environments) {
74
75 # Compose the name of the Controller
76 my $env_class = ucfirst($environment);
77 my $provider_controller_name = "Controller::${provider_class}::${env_class}";
78
79 # Compose its namespace - i.e. the STOMP queue name
80 my $namespace = $environment . '_' . $provider_class->name;
81 $self->_app->config( $provider_controller_name => { namespace => $namespace } );
82
83 # Create the class with Moose
84 my $provider = Moose::Meta::Class->create("PaymentApp::${provider_controller_name}");
85 $provider->superclasses('PaymentApp::ControllerBase::Message');
86
87 # XXX from interface role, not static list here!
88 my @dispatchable_methods = qw/ payment_auth_request
89 payment_settle_request
90 payment_refund_request
91 /;
92
93 # Attach a method for each action, making sure
94 # to apply the right method attribute to turn
95 # these into actions
96 for my $method_name (@dispatchable_methods) {
97 my $sub = sub {
98 my ($self, $c, $message) = @_;
99 my $provider_model = $c->model($provider_class);
100 my $response = $provider_model->$method_name($message);
101 $c->stash->{response} = $response;
102 };
103
104 # Why doesn't add_method return the method?
105 $provider->add_method($method_name, $sub);
106 my $method = $provider->get_method($method_name);
107 $provider->register_method_attributes($method->body, ['Local']);
108 }
109 }
110 }
111
112 return $self;
113}
114
115__PACKAGE__->meta->make_immutable;
116