Commit | Line | Data |
3e560748 |
1 | package Catalyst::Component::DelayedInstance; |
2 | |
3 | use Moose::Role; |
4 | |
5 | around 'COMPONENT', sub { |
6 | my ($orig, $class, $app, $conf) = @_; |
7 | my $method = $class->can('build_delayed_instance') ? |
8 | 'build_delayed_instance' : 'COMPONENT'; |
9 | |
10 | return bless sub { my $c = shift; $class->$method($app, $conf) }, $class; |
11 | }; |
12 | |
13 | our $SINGLE; |
14 | |
15 | sub ACCEPT_CONTEXT { |
16 | my ($self, $c, @args) = @_; |
17 | $c->log->warn("Component ${\$self->catalyst_component_name} cannot be called with arguments") |
18 | if $c->debug and scalar(@args) > 0; |
19 | |
20 | return $SINGLE ||= $self->(); |
21 | } |
22 | |
23 | sub AUTOLOAD { |
24 | my ($self, @args) = @_; |
25 | my $method = our $AUTOLOAD; |
26 | $method =~ s/.*:://; |
27 | |
28 | warn $method; |
29 | use Devel::Dwarn; |
30 | Dwarn \@args; |
31 | |
32 | return ($SINGLE ||= $self->())->$method(@args); |
33 | } |
34 | |
35 | 1; |
36 | |
37 | =head1 NAME |
38 | |
39 | Catalyst::Component::DelayedInstance - Moose Role for components which setup |
40 | |
41 | =head1 SYNOPSIS |
42 | |
43 | package MyApp::Model::Foo; |
44 | |
45 | use Moose; |
46 | extends 'Catalyst::Model'; |
47 | with 'Catalyst::Component::DelayedInstance'; |
48 | |
49 | sub build_per_application_instance { |
50 | my ($class, $app, $config) = @_; |
51 | |
52 | $config->{bar} = $app->model("Baz"); |
53 | return $class->new($config); |
54 | } |
55 | |
56 | =head1 DESCRIPTION |
57 | |
58 | Sometimes you want an application scoped component that nevertheless needs other |
59 | application components as part of its setup. In the past this was not reliable |
60 | since Application scoped components are setup in linear order. You could not |
61 | call $app->model in a COMPONENT method and expect 'Foo' to be there. This role |
62 | defers creating the application scoped instance until after your application is |
63 | fully setup. This means you can now assume your other application scoped components |
64 | (components that do COMPONENT but not ACCEPT_CONTEXT) are available as dependencies. |
65 | |
66 | Please note this means that your instance is not created until the first time its |
67 | called in a request. As a result any errors with configuration will not show up |
68 | until later in runtime. So there is a larger burden on your testing to make sure |
69 | your application startup and runtime is accurate. Also note that even though your |
70 | instance creation is deferred to request time, the request context is NOT given, |
71 | but the application is (this means that you cannot depend on components that do |
72 | ACCEPT_CONTEXT, since you don't have one...). |
73 | |
74 | =head1 ATTRIBUTES |
75 | |
76 | =head1 METHODS |
77 | |
78 | =head2 ACCEPT_CONTEXT |
79 | |
80 | =head2 AUTOLOAD |
81 | |
82 | =head1 SEE ALSO |
83 | |
84 | L<Catalyst::Component>, |
85 | |
86 | =head1 AUTHORS |
87 | |
88 | See L<Catalyst>. |
89 | |
90 | =head1 COPYRIGHT |
91 | |
92 | See L<Catalyst>. |
93 | |
94 | =cut |