use Hash::Util qw/lock_hash/;
use MooseX::Types::LoadableClass qw/ LoadableClass /;
use Moose::Util;
+use Catalyst::IOC::BlockInjection;
use Catalyst::IOC::ConstructorInjection;
use Module::Pluggable::Object ();
use namespace::autoclean;
);
has application_name => (
- is => 'ro',
- isa => 'Str',
- default => 'MyApp',
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
);
has sub_container_class => (
my $config = $self->resolve( service => 'config' );
$self->add_sub_container(
+ $self->build_component_subcontainer
+ );
+
+ $self->add_sub_container(
$self->build_controller_subcontainer
);
);
}
+sub build_component_subcontainer {
+ my $self = shift;
+
+ return Bread::Board::Container->new(
+ name => 'component',
+ );
+}
+
sub build_application_name_service {
my $self = shift;
}
sub find_component {
- my ( $self, $component, $c, @args ) = @_;
+ my ( $self, $component, @args ) = @_;
my ( $type, $name ) = _get_component_type_name($component);
my @result;
return $self->get_component_from_sub_container(
- $type, $name, $c, @args
+ $type, $name, @args
) if $type;
my $query = ref $component
my @components = $subcontainer->get_service_list;
@result = grep { m{$component} } @components;
- return map { $subcontainer->get_component( $_, $c, @args ) } @result
+ return map { $subcontainer->get_component( $_, @args ) } @result
if @result;
}
- # FIXME - I guess I shouldn't be calling $c->components here
# one last search for things like $c->comp(qr/::M::/)
@result = $self->find_component_regexp(
- $c->components, $component, $c, @args
+ $component, @args
) if !@result and ref $component;
# it expects an empty list on failed searches
}
sub find_component_regexp {
- my ( $self, $components, $component, @args ) = @_;
+ my ( $self, $component, @args ) = @_;
my @result;
- my @components = grep { m{$component} } keys %{ $components };
+ my @components = grep { m{$component} } keys %{ $self->get_all_components };
for (@components) {
my ($type, $name) = _get_component_type_name($_);
for my $sub_container_name (qw/model view controller/) {
my $sub_container = $self->get_sub_container($sub_container_name);
for my $service ( $sub_container->get_service_list ) {
- my $comp = $self->resolve(service => $service);
+ my $comp = $sub_container->resolve(service => $service);
my $compname = ref $comp || $comp;
my $type = ref $comp ? 'instance' : 'class';
push @comps_names_types, [ $compname, $type ];
my $self = shift;
my %components;
- my $containers = {
- map { $_ => $self->get_sub_container($_) } qw(model view controller)
- };
+ my $container = $self->get_sub_container('component');
- for my $container (keys %$containers) {
- for my $component ($containers->{$container}->get_service_list) {
- my $comp = $containers->{$container}->resolve(
- service => $component
- );
- my $comp_name = ref $comp || $comp;
- $components{$comp_name} = $comp;
- }
+ for my $component ($container->get_service_list) {
+ my $comp = $container->resolve(
+ service => $component
+ );
+ my $comp_name = ref $comp || $comp;
+ $components{$comp_name} = $comp;
}
return lock_hash %components;
return unless $type;
- $self->get_sub_container($type)->add_service(
+ my $component_service_name = "${type}_${name}";
+
+ # The 'component' sub-container will create the object, and store it's
+ # instance, which, by default, will live throughout the application.
+ # The model/view/controller sub-containers only reference the instance
+ # held in the aforementioned sub-container, and execute the ACCEPT_CONTEXT
+ # sub every time they are called, when it exists.
+ my $instance_container = $self->get_sub_container('component');
+ my $accept_context_container = $self->get_sub_container($type);
+
+ $instance_container->add_service(
Catalyst::IOC::ConstructorInjection->new(
- name => $name,
+ name => $component_service_name,
class => $component,
+ lifecycle => 'Singleton',
dependencies => [
depends_on( '/application_name' ),
depends_on( '/config' ),
],
- parameters => {
- suffix => {
- isa => 'Str',
- default => Catalyst::Utils::class2classsuffix( $component ),
- },
- accept_context_args => {
- isa => 'ArrayRef|Undef',
- required => 0,
- default => undef,
- },
- },
)
- );
+ ) unless $instance_container->has_service( $component_service_name );
+ # ^ custom containers might have added the service already.
+ # we don't want to override that.
+
+ $accept_context_container->add_service(
+ Catalyst::IOC::BlockInjection->new(
+ name => $name,
+ dependencies => [
+ depends_on( "/component/$component_service_name" ),
+ ],
+ block => sub { shift->param($component_service_name) },
+ )
+ ) unless $accept_context_container->has_service( $name );
+ # ^ same as above
}
# FIXME: should this sub exist?
=head1 Building Containers
+=head2 build_component_subcontainer
+
+Container that stores all components, i.e. all models, views and controllers
+together. Each service is an instance of the actual component, and by default
+it lives while the application is running. Retrieving components from this
+subcontainer will instantiate the component, if it hasn't been instantiated
+already, but will not execute ACCEPT_CONTEXT.
+
=head2 build_model_subcontainer
-Container that stores all models.
+Container that stores references for all models that are inside the components
+subcontainer. Retrieving a model triggers ACCEPT_CONTEXT, if it exists.
=head2 build_view_subcontainer
-Container that stores all views.
+Same as L<build_model_subcontainer>, but for views.
=head2 build_controller_subcontainer
-Container that stores all controllers.
+Same as L<build_model_subcontainer>, but for controllers. The difference is
+that there is no ACCEPT_CONTEXT for controllers.
=head1 Building Services
The parameter list is split on comma (C<,>). You can override this method to
do your own string munging, or you can define your own macros in
-C<MyApp-E<gt>config-E<gt>{ 'Plugin::ConfigLoader' }-E<gt>{ substitutions }>.
+C<< <MyApp->config( 'Plugin::ConfigLoader' => { substitutions => { ... } } ) >>.
Example:
- MyApp->config->{ 'Plugin::ConfigLoader' }->{ substitutions } = {
- baz => sub { my $c = shift; qux( @_ ); }
- }
+ MyApp->config( 'Plugin::ConfigLoader' => {
+ substitutions => {
+ baz => sub { my $c = shift; qux( @_ ); },
+ },
+ });
The above will respond to C<__baz(x,y)__> in config strings.
Reads config from local_files.
+=head2 build_class_config_service
+
+Reads config set from the application's class attribute config,
+i.e. MyApp->config( name => 'MyApp', ... )
+
=head2 build_config_path_service
Splits the path to the config file, and returns on array ref containing