PluginProbe
Packeta / trunk
Packeta vtrunk
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / deps / nette / di / src / DI / ContainerBuilder.php

ContainerBuilder.php in Packeta trunk, at deps/nette/di/src/DI/ContainerBuilder.php

324 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7 declare (strict_types=1);
8 namespace Packetery\Nette\DI;
9
10 use Packetery\Nette;
11 use Packetery\Nette\DI\Definitions\Definition;
12 /**
13 * Container builder.
14 */
15 class ContainerBuilder
16 {
17 use \Packetery\Nette\SmartObject;
18 public const ThisService = 'self', ThisContainer = 'container';
19 /** @deprecated use ContainerBuilder::ThisService */
20 public const THIS_SERVICE = self::ThisService;
21 /** @deprecated use ContainerBuilder::ThisContainer */
22 public const THIS_CONTAINER = self::ThisContainer;
23 /** @var array */
24 public $parameters = [];
25 /** @var Definition[] */
26 private $definitions = [];
27 /** @var array of alias => service */
28 private $aliases = [];
29 /** @var Autowiring */
30 private $autowiring;
31 /** @var bool */
32 private $needsResolve = \true;
33 /** @var bool */
34 private $resolving = \false;
35 /** @var array */
36 private $dependencies = [];
37 public function __construct()
38 {
39 $this->autowiring = new Autowiring($this);
40 $this->addImportedDefinition(self::ThisContainer)->setType(Container::class);
41 }
42 /**
43 * Adds new service definition.
44 * @return Definitions\ServiceDefinition
45 */
46 public function addDefinition(?string $name, ?Definition $definition = null) : Definition
47 {
48 $this->needsResolve = \true;
49 if ($name === null) {
50 for ($i = 1; isset($this->definitions['0' . $i]) || isset($this->aliases['0' . $i]); $i++) {
51 }
52 $name = '0' . $i;
53 // prevents converting to integer in array key
54 } elseif (\is_int(\key([$name => 1])) || !\preg_match('#^\\w+(\\.\\w+)*$#D', $name)) {
55 throw new \Packetery\Nette\InvalidArgumentException(\sprintf("Service name must be a alpha-numeric string and not a number, '%s' given.", $name));
56 } else {
57 $name = $this->aliases[$name] ?? $name;
58 if (isset($this->definitions[$name])) {
59 throw new \Packetery\Nette\InvalidStateException(\sprintf("Service '%s' has already been added.", $name));
60 }
61 $lname = \strtolower($name);
62 foreach ($this->definitions as $nm => $foo) {
63 if ($lname === \strtolower($nm)) {
64 throw new \Packetery\Nette\InvalidStateException(\sprintf("Service '%s' has the same name as '%s' in a case-insensitive manner.", $name, $nm));
65 }
66 }
67 }
68 $definition = $definition ?: new Definitions\ServiceDefinition();
69 $definition->setName($name);
70 $definition->setNotifier(function () : void {
71 $this->needsResolve = \true;
72 });
73 return $this->definitions[$name] = $definition;
74 }
75 public function addAccessorDefinition(?string $name) : Definitions\AccessorDefinition
76 {
77 return $this->addDefinition($name, new Definitions\AccessorDefinition());
78 }
79 public function addFactoryDefinition(?string $name) : Definitions\FactoryDefinition
80 {
81 return $this->addDefinition($name, new Definitions\FactoryDefinition());
82 }
83 public function addLocatorDefinition(?string $name) : Definitions\LocatorDefinition
84 {
85 return $this->addDefinition($name, new Definitions\LocatorDefinition());
86 }
87 public function addImportedDefinition(?string $name) : Definitions\ImportedDefinition
88 {
89 return $this->addDefinition($name, new Definitions\ImportedDefinition());
90 }
91 /**
92 * Removes the specified service definition.
93 */
94 public function removeDefinition(string $name) : void
95 {
96 $this->needsResolve = \true;
97 $name = $this->aliases[$name] ?? $name;
98 unset($this->definitions[$name]);
99 }
100 /**
101 * Gets the service definition.
102 */
103 public function getDefinition(string $name) : Definition
104 {
105 $service = $this->aliases[$name] ?? $name;
106 if (!isset($this->definitions[$service])) {
107 throw new MissingServiceException(\sprintf("Service '%s' not found.", $name));
108 }
109 return $this->definitions[$service];
110 }
111 /**
112 * Gets all service definitions.
113 * @return Definition[]
114 */
115 public function getDefinitions() : array
116 {
117 return $this->definitions;
118 }
119 /**
120 * Does the service definition or alias exist?
121 */
122 public function hasDefinition(string $name) : bool
123 {
124 $name = $this->aliases[$name] ?? $name;
125 return isset($this->definitions[$name]);
126 }
127 public function addAlias(string $alias, string $service) : void
128 {
129 if (!$alias) {
130 // builder is not ready for falsy names such as '0'
131 throw new \Packetery\Nette\InvalidArgumentException(\sprintf("Alias name must be a non-empty string, '%s' given.", $alias));
132 } elseif (!$service) {
133 // builder is not ready for falsy names such as '0'
134 throw new \Packetery\Nette\InvalidArgumentException(\sprintf("Service name must be a non-empty string, '%s' given.", $service));
135 } elseif (isset($this->aliases[$alias])) {
136 throw new \Packetery\Nette\InvalidStateException(\sprintf("Alias '%s' has already been added.", $alias));
137 } elseif (isset($this->definitions[$alias])) {
138 throw new \Packetery\Nette\InvalidStateException(\sprintf("Service '%s' has already been added.", $alias));
139 }
140 $this->aliases[$alias] = $service;
141 }
142 /**
143 * Removes the specified alias.
144 */
145 public function removeAlias(string $alias) : void
146 {
147 unset($this->aliases[$alias]);
148 }
149 /**
150 * Gets all service aliases.
151 */
152 public function getAliases() : array
153 {
154 return $this->aliases;
155 }
156 /**
157 * @param string[] $types
158 * @return static
159 */
160 public function addExcludedClasses(array $types)
161 {
162 $this->needsResolve = \true;
163 $this->autowiring->addExcludedClasses($types);
164 return $this;
165 }
166 /**
167 * Resolves autowired service name by type.
168 * @param bool $throw exception if service doesn't exist?
169 * @return ($throw is true ? string : ?string)
170 * @throws MissingServiceException
171 */
172 public function getByType(string $type, bool $throw = \false) : ?string
173 {
174 $this->needResolved();
175 return $this->autowiring->getByType($type, $throw);
176 }
177 /**
178 * Gets autowired service definition of the specified type.
179 * @throws MissingServiceException
180 */
181 public function getDefinitionByType(string $type) : Definition
182 {
183 return $this->getDefinition($this->getByType($type, \true));
184 }
185 /**
186 * Gets the autowired service names and definitions of the specified type.
187 * @return Definition[] service name is key
188 * @internal
189 */
190 public function findAutowired(string $type) : array
191 {
192 $this->needResolved();
193 return $this->autowiring->findByType($type);
194 }
195 /**
196 * Gets the service names and definitions of the specified type.
197 * @return Definition[] service name is key
198 */
199 public function findByType(string $type) : array
200 {
201 $this->needResolved();
202 $found = [];
203 foreach ($this->definitions as $name => $def) {
204 if (\is_a($def->getType(), $type, \true)) {
205 $found[$name] = $def;
206 }
207 }
208 return $found;
209 }
210 /**
211 * Gets the service names and tag values.
212 * @return array of [service name => tag attributes]
213 */
214 public function findByTag(string $tag) : array
215 {
216 $found = [];
217 foreach ($this->definitions as $name => $def) {
218 if (($tmp = $def->getTag($tag)) !== null) {
219 $found[$name] = $tmp;
220 }
221 }
222 return $found;
223 }
224 /********************* building ****************d*g**/
225 /**
226 * Checks services, resolves types and rebuilts autowiring classlist.
227 */
228 public function resolve() : void
229 {
230 if ($this->resolving) {
231 return;
232 }
233 $this->resolving = \true;
234 $resolver = new Resolver($this);
235 foreach ($this->definitions as $def) {
236 $resolver->resolveDefinition($def);
237 }
238 $this->autowiring->rebuild();
239 $this->resolving = $this->needsResolve = \false;
240 }
241 private function needResolved() : void
242 {
243 if ($this->resolving) {
244 throw new NotAllowedDuringResolvingException();
245 } elseif ($this->needsResolve) {
246 $this->resolve();
247 }
248 }
249 public function complete() : void
250 {
251 $this->resolve();
252 foreach ($this->definitions as $def) {
253 $def->setNotifier(null);
254 }
255 $resolver = new Resolver($this);
256 foreach ($this->definitions as $def) {
257 $resolver->completeDefinition($def);
258 }
259 }
260 /**
261 * Adds item to the list of dependencies.
262 * @param \ReflectionClass|\ReflectionFunctionAbstract|string $dep
263 * @return static
264 * @internal
265 */
266 public function addDependency($dep)
267 {
268 $this->dependencies[] = $dep;
269 return $this;
270 }
271 /**
272 * Returns the list of dependencies.
273 */
274 public function getDependencies() : array
275 {
276 return $this->dependencies;
277 }
278 /** @internal */
279 public function exportMeta() : array
280 {
281 $defs = $this->definitions;
282 \ksort($defs);
283 foreach ($defs as $name => $def) {
284 if ($def instanceof Definitions\ImportedDefinition) {
285 $meta['types'][$name] = $def->getType();
286 }
287 foreach ($def->getTags() as $tag => $value) {
288 $meta['tags'][$tag][$name] = $value;
289 }
290 }
291 $meta['aliases'] = $this->aliases;
292 \ksort($meta['aliases']);
293 $all = [];
294 foreach ($this->definitions as $name => $def) {
295 if ($type = $def->getType()) {
296 foreach (\class_parents($type) + \class_implements($type) + [$type] as $class) {
297 $all[$class][] = $name;
298 }
299 }
300 }
301 [$low, $high] = $this->autowiring->getClassList();
302 foreach ($all as $class => $names) {
303 $meta['wiring'][$class] = \array_filter([$high[$class] ?? [], $low[$class] ?? [], \array_diff($names, $low[$class] ?? [], $high[$class] ?? [])]);
304 }
305 return $meta;
306 }
307 public static function literal(string $code, ?array $args = null) : \Packetery\Nette\PhpGenerator\PhpLiteral
308 {
309 return new \Packetery\Nette\PhpGenerator\PhpLiteral($args === null ? $code : (new \Packetery\Nette\PhpGenerator\Dumper())->format($code, ...$args));
310 }
311 /** @deprecated */
312 public function formatPhp(string $statement, array $args) : string
313 {
314 \array_walk_recursive($args, function (&$val) : void {
315 if ($val instanceof \Packetery\Nette\DI\Definitions\Statement) {
316 $val = (new Resolver($this))->completeStatement($val);
317 } elseif ($val instanceof Definition) {
318 $val = new Definitions\Reference($val->getName());
319 }
320 });
321 return (new PhpGenerator($this))->formatPhp($statement, $args);
322 }
323 }
324