407
|
1 package IMPL::Config::Container;
|
412
|
2 use strict;
|
|
3
|
413
|
4 use IMPL::Exception();
|
412
|
5 use IMPL::lang qw(:base);
|
|
6 use IMPL::declare {
|
|
7 require => {
|
413
|
8 Descriptor => 'IMPL::Config::Descriptor',
|
|
9 ValueDescriptor => 'IMPL::Config::ValueDescriptor',
|
|
10 ActivationContext => 'IMPL::Config::ActivationContext',
|
|
11 Hierarchy => 'IMPL::Config::Hierarchy',
|
|
12 Bag => 'IMPL::Config::Bag'
|
412
|
13 },
|
|
14 base => [
|
|
15 'IMPL::Object' => undef
|
|
16 ],
|
|
17 props => [
|
413
|
18 roles => 'r',
|
|
19 services => 'r',
|
|
20 instances => 'r',
|
|
21 parent => 'r'
|
412
|
22 ]
|
|
23 };
|
|
24
|
|
25 my $nextRoleId = 1;
|
|
26
|
413
|
27 sub CTOR {
|
|
28 my ( $this, $parent ) = @_;
|
|
29
|
|
30 $this->instances( {} );
|
|
31
|
|
32 if ($parent) {
|
|
33 $this->roles( Hierarchy->new( $parent->roles ) );
|
|
34 $this->services( Bag->new( $parent->services ) );
|
|
35 $this->parent($parent);
|
|
36 }
|
|
37 else {
|
|
38 $this->roles( Hierarchy->new() );
|
|
39 $this->services( Bag->new() );
|
|
40 }
|
|
41 }
|
412
|
42
|
|
43 sub Register {
|
413
|
44 my ( $this, $role, $service ) = @_;
|
|
45
|
|
46 die IMPL::InvalidArgumentException->new(
|
|
47 role => 'The argument is required' )
|
|
48 unless $role;
|
|
49 die IMPL::InvalidArgumentException->new('service')
|
|
50 unless is( $service, Descriptor );
|
|
51
|
|
52 if ( isarray($role) ) {
|
|
53 my $tempRole = "unnamed-" . $nextRoleId++;
|
|
54 $this->role->AddRole( $tempRole, $role );
|
|
55 $role = $tempRole;
|
412
|
56 }
|
413
|
57
|
|
58 $service = ValueDescriptor->new( value => $service )
|
|
59 unless is( $service, Descriptor );
|
|
60
|
|
61 $this->services->Register( $role, $this->roles->GetLinearRoleHash($role), $service );
|
|
62 }
|
|
63
|
|
64 sub Resolve {
|
|
65 my ( $this, $role, %opts ) = @_;
|
|
66
|
|
67 my $descriptor = $this->services->Resolve($role);
|
|
68
|
|
69 return $descriptor->Activate( ActivationContext->new($this) )
|
|
70 if $descirptor;
|
|
71
|
|
72 return $opts{default} if exists $opts{default};
|
|
73 }
|
|
74
|
|
75 sub ResolveAll {
|
|
76 my ( $this, $role, %opts ) = @_;
|
|
77
|
|
78 my $all = $this->services->ResolveAll($role);
|
|
79
|
|
80 my $context;
|
|
81
|
|
82 my @result;
|
|
83
|
|
84 foreach my $service (@$all) {
|
|
85 $context = ActivationContext->new($this)
|
|
86 unless $context || $opts{shared};
|
|
87
|
|
88 push @result, $service->Activate($context);
|
|
89 }
|
|
90
|
|
91 return \@result;
|
412
|
92 }
|
407
|
93
|
|
94 1;
|
|
95
|
|
96 __END__
|
|
97
|
|
98 =pod
|
|
99
|
|
100 =head1 NAME
|
|
101
|
|
102 C<IMPL::Config::Container> - dependency injection container
|
|
103
|
|
104 =head1 SYNOPSIS
|
|
105
|
|
106 =head2 METHODS
|
|
107
|
|
108 =head3 GetService($serviceId)
|
|
109
|
|
110 =over
|
|
111
|
|
112 =item * $serviceId
|
|
113
|
|
114 A string indetifier of the service, it can be in two forms: class name or service name,
|
|
115 for the class name it should be prefixed with C<@>, for example: C<@Foo::Bar>.
|
|
116
|
|
117 =back
|
|
118
|
|
119 The activation container maintains two maps, one for classes and the other for names.
|
|
120 The first one is useful when we searching for an implementation the second one when
|
|
121 we need a particular service.
|
|
122
|
|
123 =head3 RegisterService($descriptor)
|
|
124
|
412
|
125 =cut
|