fixes and cleanup
[catagits/Catalyst-Runtime.git] / lib / Catalyst / IOC.pm
1 package Catalyst::IOC;
2 use strict;
3 use warnings;
4 use Bread::Board qw/depends_on/;
5 use Catalyst::IOC::ConstructorInjection;
6
7 use Sub::Exporter -setup => {
8     exports => [qw/
9         depends_on
10         component
11         model
12         view
13         controller
14         container
15     /],
16     groups  => { default => [qw/
17         depends_on
18         component
19         model
20         view
21         controller
22         container
23     /]},
24 };
25
26 sub container (&) {
27     my $code = shift;
28     my $caller = caller;
29
30     no strict 'refs';
31     ${"${caller}::customise_container"} = sub {
32         local ${"${caller}::current_container"} = shift;
33         $code->();
34     };
35 }
36
37 sub model (&)      { _subcontainer( shift, (caller)[0], 'model' )      }
38 sub view (&)       { _subcontainer( shift, (caller)[0], 'view' )       }
39 sub controller (&) { _subcontainer( shift, (caller)[0], 'controller' ) }
40
41 sub _subcontainer (&$$) {
42     my ( $code, $caller, $subcontainer ) = @_;
43
44     no strict 'refs';
45     local ${"${caller}::current_container"} =
46         ${"${caller}::current_container"}->get_sub_container($subcontainer);
47     $code->();
48 }
49
50 sub component ($;%) {
51     my ($name, %args) = @_;
52     my $current_container;
53
54     {
55         no strict 'refs';
56         my $caller = caller;
57         $current_container = ${"${caller}::current_container"};
58     }
59
60     $args{dependencies} ||= {};
61     $args{dependencies}{application_name} = depends_on( '/application_name' );
62
63     my $lifecycle    = $args{lifecycle} || 'Singleton';
64     $args{lifecycle} = grep( m/^$lifecycle$/, qw/COMPONENTSingleton Request/)
65                      ? "+Catalyst::IOC::LifeCycle::$lifecycle"
66                      : $lifecycle
67                      ;
68
69     # FIXME - check $args{type} here!
70
71     my $component_name = join '::', (
72         $current_container->resolve(service => '/application_name'),
73         ucfirst($current_container->name),
74         $name
75     );
76
77     $current_container->add_service(
78         Catalyst::IOC::ConstructorInjection->new(
79             %args,
80             name => $name,
81             catalyst_component_name => $component_name,
82         )
83     );
84 }
85
86 1;
87
88 __END__
89
90 =pod
91
92 =head1 NAME
93
94 Catalyst::IOC - IOC for Catalyst, based on Bread::Board
95
96 =head1 SYNOPSIS
97
98     package MyApp::Container;
99     use Moose;
100     use Catalyst::IOC;
101     extends 'Catalyst::IOC::Container';
102
103     container {
104         model {
105             # default component
106             component Foo => ();
107
108             # model Bar needs model Foo to be built before
109             # and Bar's constructor gets Foo as a parameter
110             component Bar => ( dependencies => [
111                 depends_on('/model/Foo'),
112             ]);
113
114             # Baz is rebuilt once per HTTP request
115             component Baz => ( lifecycle => 'Request' );
116
117             # built only once per application life time
118             component Quux => ( lifecycle => 'Singleton' );
119
120             # built once per app life time and uses an external model,
121             # outside the default directory
122             # no need for wrappers or Catalyst::Model::Adaptor
123             component Fnar => (
124                 lifecycle => 'Singleton',
125                 class => 'My::External::Class',
126             );
127         };
128         view {
129             component HTML => ();
130         };
131         controller {
132             component Root => ();
133         };
134     }
135
136 =head1 DESCRIPTION
137
138 Catalyst::IOC provides "sugar" methods to extend the behavior of the default
139 Catalyst container.
140
141 =head1 METHODS
142
143 =head2 container
144
145 Sets up the root container to be customised.
146
147 =head2 model
148
149 Sets up the model container to be customised.
150
151 =head2 view
152
153 Sets up the view container to be customised.
154
155 =head2 controller
156
157 Sets up the controller container to be customised.
158
159 =head2 component
160
161 Adds a component to the subcontainer. Works like L<Bread::Board::service>.
162
163 =head1 AUTHORS
164
165 Catalyst Contributors, see Catalyst.pm
166
167 =head1 SEE ALSO
168
169 L<Bread::Board>
170
171 =head1 COPYRIGHT
172
173 This library is free software. You can redistribute it and/or modify it under
174 the same terms as Perl itself.
175
176 =cut