}
# Filter a component before returning by calling ACCEPT_CONTEXT if available
+
+#our %tracker = ();
sub _filter_component {
my ( $c, $comp, @args ) = @_;
+ # die "Circular Dependencies Detected." if $tracker{$comp};
+ # $tracker{$comp}++;
+ if(ref $comp eq 'CODE') {
+ $comp = $comp->($c);
+ }
+ #$tracker{$comp}++;
+
if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
return $comp->ACCEPT_CONTEXT( $c, @args );
}
+ $c->log->warn("You called component '${\$comp->catalyst_component_name}' with arguments [@args], but this component does not ACCEPT_CONTEXT, so args are ignored.") if scalar(@args) && $c->debug;
+
return $comp;
}
$c->model('Foo')->do_stuff;
-Any extra arguments are directly passed to ACCEPT_CONTEXT.
+Any extra arguments are directly passed to ACCEPT_CONTEXT, if the model
+defines ACCEPT_CONTEXT. If it does not, the args are discarded.
If the name is omitted, it will look for
- a model object in $c->stash->{current_model_instance}, then
}
for my $component (@comps) {
- my $instance = $class->components->{ $component } = $class->setup_component($component);
- my @expanded_components = $instance->can('expand_modules')
- ? $instance->expand_modules( $component, $config )
- : $class->expand_component_module( $component, $config );
- for my $component (@expanded_components) {
- next if $comps{$component};
- $class->components->{ $component } = $class->setup_component($component);
- }
+ my $instance = $class->components->{ $component } = $class->delayed_setup_component($component);
}
- # Inject a component or wrap a stand alone class in an adaptor
- #my @configured_comps = grep { not($class->component($_)||'') }
- # grep { /^(Model)::|(View)::|(Controller::)/ }
- # keys %{$class->config ||+{}};
+ # Inject a component or wrap a stand alone class in an adaptor. This makes a list
+ # of named components in the configuration that are not actually existing (not a
+ # real file).
+
+ my @injected_components = keys %{$class->config->{inject_components} ||+{}};
+ foreach my $injected_comp_name(@injected_components) {
+ my $component_class = $class->config->{inject_components}->{$injected_comp_name}->{from_component} || '';
+ if($component_class) {
+ my @roles = @{$class->config->{inject_components}->{$injected_comp_name}->{roles} ||[]};
+ my %args = %{ $class->config->{$injected_comp_name} || +{} };
+
+ Catalyst::Utils::inject_component(
+ into => $class,
+ component => $component_class,
+ (scalar(@roles) ? (traits => \@roles) : ()),
+ as => $injected_comp_name);
+ }
+ }
+
+ # All components are registered, now we need to 'init' them.
+ foreach my $component_name (keys %{$class->components||{}}) {
+ $class->components->{$component_name} = $class->components->{$component_name}->() if
+ (ref($class->components->{$component_name}) || '') eq 'CODE';
+ }
+}
+
+=head2 $app->inject_components($MyApp_Component_name => \%args);
+
+Add a component that is injected at setup:
+
+ MyApp->inject_component( 'Model::Foo' => { from_component => 'Common::Foo' } );
+
+Must be called before ->setup. Expects a component name for your
+current application and \%args where
+
+=over 4
+
+=item from_component
+
+The target component being injected into your application
+
+=item roles
+
+An arrayref of L<Moose::Role>s that are applied to your component.
+
+=back
+
+Example
+
+ MyApp->inject_component(
+ 'Model::Foo' => {
+ from_component => 'Common::Model::Foo',
+ roles => ['Role1', 'Role2'],
+ });
- #foreach my $configured_comp(@configured_comps) {
- #warn $configured_comp;
- #}
+=head2 $app->inject_components
+
+Inject a list of components:
+
+ MyApp->inject_components(
+ 'Model::FooOne' => {
+ from_component => 'Common::Model::Foo',
+ roles => ['Role1', 'Role2'],
+ },
+ 'Model::FooTwo' => {
+ from_component => 'Common::Model::Foo',
+ roles => ['Role1', 'Role2'],
+ });
+
+=cut
+
+sub inject_component {
+ my ($app, $name, $args) = @_;
+ die "Component $name exists" if
+ $app->config->{inject_components}->{$name};
+ $app->config->{inject_components}->{$name} = $args;
+}
+
+sub inject_components {
+ my $app = shift;
+ while(@_) {
+ $app->inject_component(shift, shift);
+ }
}
=head2 $c->locate_components( $setup_component_config )
return Devel::InnerPackage::list_packages( $module );
}
+=head2 $app->delayed_setup_component
+
+Returns a coderef that points to a setup_component instance. Used
+internally for when you want to delay setup until the first time
+the component is called.
+
+=cut
+
+sub delayed_setup_component {
+ my($class, $component, @more) = @_;
+ return sub {
+ return my $instance = $class->setup_component($component, @more);
+ };
+}
+
=head2 $c->setup_component
=cut
# for the debug screen, as $component is already the key name.
local $config->{catalyst_component_name} = $component;
- my $instance = eval { $component->COMPONENT( $class, $config ); };
-
- if ( my $error = $@ ) {
- chomp $error;
- Catalyst::Exception->throw(
- message => qq/Couldn't instantiate component "$component", "$error"/
- );
- }
+ my $instance = eval {
+ $component->COMPONENT( $class, $config );
+ } || do {
+ my $error = $@;
+ chomp $error;
+ Catalyst::Exception->throw(
+ message => qq/Couldn't instantiate component "$component", "$error"/
+ );
+ };
unless (blessed $instance) {
my $metaclass = Moose::Util::find_meta($component);
qq/Couldn't instantiate component "$component", COMPONENT() method (from $component_method_from) didn't return an object-like value (value was $value)./
);
}
- return $instance;
+
+ my @expanded_components = $instance->can('expand_modules')
+ ? $instance->expand_modules( $component, $config )
+ : $class->expand_component_module( $component, $config );
+ for my $component (@expanded_components) {
+ next if $class->components->{ $component };
+ $class->components->{ $component } = $class->setup_component($component);
+ }
+
+ return $instance;
}
=head2 $c->setup_dispatcher