d63564598a2f49e70345d8102855f946dcddcf0d
[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 no strict 'refs';
7
8 # FIXME - All of these imports need to get the importing package
9 #         as the customise_container and current_container variables
10 #         NEED to be in the containers package so there can be multiple
11 #         containers..
12 use Sub::Exporter -setup => {
13     exports => [qw/
14         depends_on
15         component
16         model
17         container
18     /],
19     groups  => { default => [qw/
20         depends_on
21         component
22         model
23         container
24     /]},
25 };
26 #use Sub::Exporter -setup => [
27 #    qw(
28 #        Bread::Board::as
29 #        Bread::Board::container
30 #        Bread::Board::depends_on
31 #        Bread::Board::service
32 #        Bread::Board::alias
33 #        Bread::Board::wire_names
34 #        Bread::Board::include
35 #        Bread::Board::typemap
36 #        Bread::Board::infer
37 #    )
38 #];
39 # I'm probably doing it wrong.
40 # Anyway, I'll just use Moose::Exporter. Do I really have to use Sub::Exporter?
41 #use Moose::Exporter;
42 #Moose::Exporter->setup_import_methods(
43 #    also => ['Bread::Board'],
44 #);
45 sub container (&) {
46     my $code = shift;
47     my $caller = caller;
48     ${"${caller}::customise_container"} = sub {
49         warn("In customise container");
50         local ${"${caller}::current_container"} = shift;
51         $code->();
52     };
53 }
54
55 sub model (&) {
56     my $code = shift;
57     my $caller = caller;
58     local ${"${caller}::current_container"} = ${"${caller}::current_container"}->get_sub_container('model');
59     $code->();
60 }
61
62 sub component {
63     my ($name, %args) = @_;
64     my $caller = caller;
65     $args{dependencies} ||= {};
66     $args{dependencies}{application_name} = depends_on( '/application_name' );
67
68     my $lifecycle = $args{lifecycle};
69     my %catalyst_lifecycles = map { $_ => 1 } qw/ COMPONENTSingleton Request /;
70     $args{lifecycle} = $lifecycle
71                      ? $catalyst_lifecycles{$lifecycle} ? "+Catalyst::IOC::LifeCycle::$lifecycle" : $lifecycle
72                      : 'Singleton'
73                      ;
74
75     # FIXME - check $args{type} here!
76
77     my $component_name = join '::', (
78         ${"${caller}::current_container"}->resolve(service => '/application_name'),
79         ucfirst(${"${caller}::current_container"}->name),
80         $name
81     );
82
83     my $service = Catalyst::IOC::ConstructorInjection->new(
84         %args,
85         name => $name,
86         catalyst_component_name => $component_name,
87     );
88     ${"${caller}::current_container"}->add_service($service);
89 }
90
91 1;
92
93 # FIXME - should the code example below be on this file or Catalyst::IOC::Container?
94
95 __END__
96
97 =pod
98
99 =head1 NAME
100
101 Catalyst::IOC - IOC for Catalyst, based on Bread::Board
102
103 =head1 SYNOPSIS
104
105     package MyApp::Container;
106     use Catalyst::IOC;
107
108     sub BUILD {
109         my $self = shift;
110
111         container $self => as {
112             container model => as {
113
114                 # default component
115                 component Foo => ();
116
117                 # model Bar needs model Foo to be built before
118                 # and Bar's constructor gets Foo as a parameter
119                 component Bar => ( dependencies => [
120                     depends_on('/model/Foo'),
121                 ]);
122
123                 # Baz is rebuilt once per HTTP request
124                 component Baz => ( lifecycle => 'Request' );
125
126                 # built only once per application life time
127                 component Quux => ( lifecycle => 'Singleton' );
128
129                 # built once per app life time and uses an external model,
130                 # outside the default directory
131                 # no need for wrappers or Catalyst::Model::Adaptor
132                 component Fnar => (
133                     lifecycle => 'Singleton',
134                     class => 'My::External::Class',
135                 );
136             };
137         }
138     }
139
140 =head1 DESCRIPTION
141
142 =head1 METHODS
143
144 =head1 AUTHORS
145
146 Catalyst Contributors, see Catalyst.pm
147
148 =head1 SEE ALSO
149
150 L<Bread::Board>
151
152 =head1 COPYRIGHT
153
154 This library is free software. You can redistribute it and/or modify it under
155 the same terms as Perl itself.
156
157 =cut