Commit | Line | Data |
d4db6430 |
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 | |