-
-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathInjectionConfig.php
More file actions
166 lines (150 loc) · 5.38 KB
/
Copy pathInjectionConfig.php
File metadata and controls
166 lines (150 loc) · 5.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<?php
declare(strict_types=1);
namespace Laminas\Di\Config;
use ArrayAccess;
use Laminas\Di\Config\Exception\InvalidConfigException;
use Laminas\Di\ConfigInterface;
use Laminas\Di\Exception\LogicException;
use function array_keys;
use function get_debug_type;
use function is_array;
use function sprintf;
/**
* Provides a typesafe and immutable DI configuration from a config array.
*
* This configures the instantiation process of the dependency injector.
*
* **Example:**
*
* <code>
* return [
* // This section provides global type preferences.
* // Those are visited if a specific instance has no preference definitions.
* 'preferences' => [
* // The key is the requested class or interface name, the values are
* // the types the dependency injector should prefer.
* Some\Interface::class => Some\Preference::class
* ],
* // This configures the instantiation of specific types.
* // Types may also be purely virtual by defining the aliasOf key.
* 'types' => [
* My\Class::class => [
* 'preferences' => [
* // this supercedes the global type preferences
* // when My\Class is instantiated
* Some\Interface::class => 'My.SpecificAlias'
* ],
*
* // instantiation parameters. These will only be used for
* // the instantiator (i.e. the constructor)
* 'parameters' => [
* 'foo' => My\FooImpl::class, // Use the given type to provide the injection (depends on definition)
* 'bar' => '*' // Use the type preferences
* ],
* ],
*
* 'My.Alias' => [
* // typeOf defines virtual classes which can be used as type
* // preferences or for newInstance calls. They allow providing
* // custom configs for a class
* 'typeOf' => Some\Class::class,
* 'preferences' => [
* Foo::class => Bar::class
* ]
* ]
* ]
* ];
* </code>
*
* ## Notes on Injections
*
* Named arguments and Automatic type lookups will only work for Methods that
* are known to the dependency injector through its definitions. Injections for
* unknown methods do not perform type lookups on its own.
*
* A value injection without any lookups can be forced by providing a
* Resolver\ValueInjection instance.
*
* To force a service/class instance provide a Resolver\TypeInjection instance.
* For classes known from the definitions, a type preference might be the
* better approach
*
* @see \Laminas\Di\Resolver\ValueInjection A container to force injection of a value
* @see \Laminas\Di\Resolver\TypeInjection A container to force looking up a specific type instance for injection
*
* @readonly
*/
final class InjectionConfig implements ConfigInterface
{
/**
* @param array<string, TypeConfig|AliasConfig> $types
*/
public function __construct(
private readonly TypePreferences $preferences = new TypePreferences(),
private readonly array $types = []
) {
}
/**
* Constructs the injection config from a laminas config value
*/
public static function fromConfigValue(mixed $config): self
{
if (! is_array($config) && ! $config instanceof ArrayAccess) {
throw new InvalidConfigException(
sprintf(
'Di configuration must be an array or implement ArrayAccess, got %s',
get_debug_type($config),
),
);
}
return new self(
TypePreferences::fromConfigValue($config['preferences'] ?? []),
TypeConfig::mapFromConfigValue($config['types'] ?? []),
);
}
private function getTypeConfig(string $name): TypeConfig|null
{
$type = $this->types[$name] ?? null;
return $type instanceof AliasConfig ? $type->type : $type;
}
public function isAlias(string $name): bool
{
$type = $this->types[$name] ?? null;
return $type instanceof AliasConfig;
}
public function getConfiguredTypeNames(): array
{
return array_keys($this->types);
}
public function getClassForAlias(string $name): string|null
{
return $this->getTypeConfig($name)?->getClassName();
}
public function getParameters(string $type): array
{
/**
* Psalm-Bug: https://github.com/vimeo/psalm/issues/7099
*
* @psalm-suppress RedundantCondition
* @psalm-suppress TypeDoesNotContainNull
*/
return $this->getTypeConfig($type)?->parameters->toArray() ?? [];
}
public function setParameters(string $type, array $params)
{
throw new LogicException(
'Injection config is considered immutable. You can set [dependencies][auto][mutableConfig] to '
. 'true to restore the previous, but deprecated, behavior'
);
}
public function getTypePreference(string $type, string|null $contextClass = null): string|null
{
if ($contextClass !== null) {
$preference = $this->getTypeConfig($contextClass)?->preferences->getPreferenceFor($type);
if ($preference !== null) {
return $preference;
}
}
return $this->preferences->getPreferenceFor($type);
}
}