Add code from gists 12311[56]
[catagits/CatalystX-DynamicComponent.git] / t / lib / TestComplexApp / Model / PaymentProvider.pm
1 package TestComplexApp::Model::PaymentProvider;
2 use Moose;
3 use Moose::Meta::Class;
4 use namespace::autoclean;
5
6 extends 'Catalyst::Model';
7
8 =head1 NAME
9
10 PaymentApp::Model::PaymentProvider - Provider Model factory
11
12 =head1 DESCRIPTION 
13
14 This module creates dynamic Catalyst Models based on configured
15 payment providers and the requested payment profile. 
16
17 The Model instance is created at request time, not at setup time, and
18 so we can inspect the message to see which enterprise and profile is
19 required. We then load that profile using the ProfileDB Model, and
20 instantiate the Model. The corresponding generated controller then
21 invokes the appropriate method on this Model.
22
23 We create a Model class per configured payment provider, and we
24 require this configuration:
25
26   Model::PaymentProvider:
27     providers:
28       - PaymentProvider::Datacash
29       - PaymentProvider::Cybersource
30       - PaymentProvider::Null
31
32 The Model instances may be accessed like so:
33
34   $c->model('PaymentProvider::Datacash')
35
36 with the enterprise and profile names in the stash.
37
38 =head1 TODO
39
40 More graceful handling of missing enterprise and/or profile. We should
41 do something other than just not return a model. 
42
43 =head1 SEE ALSO
44
45 PaymentApp::Controller::PaymentProvider - this module's partner in crime.
46
47 =cut
48
49 sub COMPONENT {
50         my $self = shift->next::method(@_);
51         
52         my $provider_classes = $self->{providers};
53
54         for my $provider_class (@$provider_classes) {
55                 eval "require $provider_class";
56                 if ($@) {
57                         die "loading $provider_class: $@";
58                 }
59                 
60                 my $provider_model_name = "PaymentApp::Model::${provider_class}";
61                 my $provider = Moose::Meta::Class->create($provider_model_name);
62                 $provider->add_method('ACCEPT_CONTEXT', 
63                                       sub {
64                                               my ($model, $c) = @_;
65                                               my $profile = $self->load_profile($c);
66                                               my $provider_model = $provider_class->new($profile);
67                                               return $provider_model;
68                                       });
69         }
70
71         return $self;
72 }
73
74 # Load the given profile and instantiate the provider
75 sub load_profile {
76         my ($self, $c) = @_;
77
78         my $profile_name = $c->stash->{profile};
79         my $enterprise_name = $c->stash->{enterprise};
80         
81         my $enterprise = $c->model('ProfileDB::Enterprise')->single(
82                 {name => $enterprise_name}
83         );
84         my $profile = $c->model('ProfileDB::Profile')->single(
85                 {name => $profile_name, enterprise_id => $enterprise->id}
86         );
87         
88         my $profile_data = {};
89         my $set_rs = $c->model('ProfileDB::ProfileSetting')->search(
90                 {profile_id => $profile->id}
91         );
92         while (my $set = $set_rs->next) {
93                 $profile_data->{$set->name} = $set->value;
94         }
95         
96         return $profile_data;
97 }
98         
99 1;
100