package Catalyst::IOC;
use strict;
use warnings;
-use Bread::Board;
+use Bread::Board qw/depends_on/;
use Catalyst::IOC::ConstructorInjection;
-# FIXME - neither of these work:
use Sub::Exporter -setup => {
exports => [qw/
+ depends_on
component
+ model
+ view
+ controller
+ container
/],
groups => { default => [qw/
+ depends_on
component
+ model
+ view
+ controller
+ container
/]},
};
-#use Sub::Exporter -setup => [
-# qw(
-# Bread::Board::as
-# Bread::Board::container
-# Bread::Board::depends_on
-# Bread::Board::service
-# Bread::Board::alias
-# Bread::Board::wire_names
-# Bread::Board::include
-# Bread::Board::typemap
-# Bread::Board::infer
-# )
-#];
-# I'm probably doing it wrong.
-# Anyway, I'll just use Moose::Exporter. Do I really have to use Sub::Exporter?
-#use Moose::Exporter;
-#Moose::Exporter->setup_import_methods(
-# also => ['Bread::Board'],
-#);
-
-sub component {
+
+sub container (&) {
+ my $code = shift;
+ my $caller = caller;
+
+ no strict 'refs';
+ ${"${caller}::customise_container"} = sub {
+ local ${"${caller}::current_container"} = shift;
+ $code->();
+ };
+}
+
+sub model (&) { &_subcontainer }
+sub view (&) { &_subcontainer }
+sub controller (&) { &_subcontainer }
+
+sub _subcontainer {
+ my $code = shift;
+
+ my ( $caller, $f, $l, $subcontainer ) = caller(1);
+ $subcontainer =~ s/^Catalyst::IOC:://;
+
+ no strict 'refs';
+ local ${"${caller}::current_container"} =
+ ${"${caller}::current_container"}->get_sub_container($subcontainer);
+ $code->();
+}
+
+sub component ($;%) {
my ($name, %args) = @_;
+ my $current_container;
+
+ {
+ no strict 'refs';
+ my $caller = caller;
+ $current_container = ${"${caller}::current_container"};
+ }
+
$args{dependencies} ||= {};
$args{dependencies}{application_name} = depends_on( '/application_name' );
+ my $lifecycle = $args{lifecycle} || 'Singleton';
+ $args{lifecycle} = grep( m/^$lifecycle$/, qw/COMPONENTSingleton Request/ )
+ ? "+Catalyst::IOC::LifeCycle::$lifecycle"
+ : $lifecycle
+ ;
+
# FIXME - check $args{type} here!
- Catalyst::IOC::ConstructorInjection->new(
- %args,
- name => $name,
- lifecycle => 'Singleton',
- # XX FIXME - needs to become possible to intuit catalyst_component_name
- # from dependencies (like config)
- catalyst_component_name => 'TestAppCustomContainer::Model::Bar',
- )
+ my $component_name = join '::', (
+ $current_container->resolve(service => '/application_name'),
+ ucfirst($current_container->name),
+ $name
+ );
+
+ $current_container->add_service(
+ Catalyst::IOC::ConstructorInjection->new(
+ %args,
+ name => $name,
+ catalyst_component_name => $component_name,
+ )
+ );
}
1;
-# FIXME - should the code example below be on this file or Catalyst::IOC::Container?
-
__END__
=pod
=head1 SYNOPSIS
package MyApp::Container;
+ use Moose;
use Catalyst::IOC;
+ extends 'Catalyst::IOC::Container';
+
+ container {
+ model {
+ # default component
+ component Foo => ();
+
+ # model Bar needs model Foo to be built before
+ # and Bar's constructor gets Foo as a parameter
+ component Bar => ( dependencies => [
+ depends_on('/model/Foo'),
+ ]);
+
+ # Baz is rebuilt once per HTTP request
+ component Baz => ( lifecycle => 'Request' );
+
+ # built only once per application life time
+ component Quux => ( lifecycle => 'Singleton' );
+
+ # built once per app life time and uses an external model,
+ # outside the default directory
+ # no need for wrappers or Catalyst::Model::Adaptor
+ component Fnar => (
+ lifecycle => 'Singleton',
+ class => 'My::External::Class',
+ );
+ };
+ view {
+ component HTML => ();
+ };
+ controller {
+ component Root => ();
+ };
+ }
- sub BUILD {
- my $self = shift;
+=head1 DESCRIPTION
- container $self => as {
- container model => as {
+Catalyst::IOC provides "sugar" methods to extend the behavior of the default
+Catalyst container.
- # default component
- component Foo => ();
+=head1 METHODS
- # model Bar needs model Foo to be built before
- # and Bar's constructor gets Foo as a parameter
- component Bar => ( dependencies => [
- depends_on('/model/Foo'),
- ]);
+=head2 container
- # Baz is rebuilt once per HTTP request
- component Baz => ( lifecycle => 'Request' );
+Sets up the root container to be customised.
- # built only once per application life time
- component Quux => ( lifecycle => 'Singleton' );
+=head2 model
- # built once per app life time and uses an external model,
- # outside the default directory
- # no need for wrappers or Catalyst::Model::Adaptor
- component Fnar => (
- lifecycle => 'Singleton',
- class => 'My::External::Class',
- );
- };
- }
- }
+Sets up the model container to be customised.
-=head1 DESCRIPTION
+=head2 view
-=head1 METHODS
+Sets up the view container to be customised.
+
+=head2 controller
+
+Sets up the controller container to be customised.
+
+=head2 component
+
+Adds a component to the sub-container. Works like L<Bread::Board::service>.
=head1 AUTHORS