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