e536ffa3a6ba3d849214909031a11729e8123999
[catagits/Catalyst-Runtime.git] / lib / Catalyst / IOC / ConstructorInjection.pm
1 package Catalyst::IOC::ConstructorInjection;
2 use Moose;
3 use Try::Tiny;
4 use Catalyst::Utils ();
5 extends 'Bread::Board::ConstructorInjection';
6
7 with 'Bread::Board::Service::WithClass',
8      'Bread::Board::Service::WithParameters',
9      'Bread::Board::Service::WithDependencies';
10
11 has config_key => (
12     is         => 'ro',
13     isa        => 'Str',
14     lazy_build => 1,
15 );
16
17 sub _build_config_key { Catalyst::Utils::class2classsuffix( shift->class ) }
18
19 sub _build_constructor_name { 'COMPONENT' }
20
21 sub get {
22     my $self = shift;
23
24     my $instance;
25
26     my $constructor = $self->constructor_name;
27     my $component   = $self->class;
28     my %params = %{ $self->params };
29     use Data::Dumper;
30     Carp::cluck("Building $component with " . Dumper(\%params));
31     my $config      = delete($params{'config'})->{ $self->config_key } || {};
32     %$config = (%$config, %params);
33
34     # FIXME - Is depending on the application name to pass into constructors here a good idea?
35     #         This makes app/ctx split harder I think.. Need to think more here, but I think
36     #         we want to pass the application in as a parameter when building the service
37     #         rather than depending on the app name, so that later, when the app becomes an instance
38     #         then it'll get passed in, and components can stash themselves 'per app instance'
39     my $app_name    = $self->param('application_name');
40
41     # Stash catalyst_component_name in the config here, so that custom COMPONENT
42     # methods also pass it. local to avoid pointlessly shitting in config
43     # for the debug screen, as $component is already the key name.
44     local $config->{catalyst_component_name} = $component;
45
46     unless ( $component->can( $constructor ) ) {
47         # FIXME - make some deprecation warnings
48         return $component;
49     }
50
51     try {
52         $instance = $component->$constructor( $app_name, $config );
53     }
54     catch {
55         Catalyst::Exception->throw(
56             message => qq/Couldn't instantiate component "$component", "$_"/
57         );
58     };
59
60     return $instance
61         if blessed $instance;
62
63     my $metaclass = Moose::Util::find_meta($component);
64     my $method_meta = $metaclass->find_method_by_name($constructor);
65     my $component_method_from = $method_meta->associated_metaclass->name;
66     my $value = defined($instance) ? $instance : 'undef';
67     Catalyst::Exception->throw(
68         message =>
69         qq/Couldn't instantiate component "$component", $constructor() method (from $component_method_from) didn't return an object-like value (value was $value)./
70     );
71 }
72
73 __PACKAGE__->meta->make_immutable;
74
75 no Moose; 1;
76
77 __END__
78
79 =pod
80
81 =head1 NAME
82
83 Catalyst::IOC::ConstructorInjection
84
85 =head1 SYNOPSIS
86
87 =head1 DESCRIPTION
88
89 =head1 AUTHORS
90
91 Catalyst Contributors, see Catalyst.pm
92
93 =head1 COPYRIGHT
94
95 This library is free software. You can redistribute it and/or modify it under
96 the same terms as Perl itself.
97
98 =cut