PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.6.1
Defender Security – Malware Scanner, Login Security & Firewall v5.6.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / lib / packages / DI / ContainerBuilder.php

ContainerBuilder.php in Defender Security – Malware Scanner, Login Security & Firewall 5.6.1, at lib/packages/DI/ContainerBuilder.php

386 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace WPMU_DEV\Defender\Vendor\DI;
6
7 use WPMU_DEV\Defender\Vendor\DI\Compiler\Compiler;
8 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\AnnotationBasedAutowiring;
9 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\DefinitionArray;
10 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\DefinitionFile;
11 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\DefinitionSource;
12 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\NoAutowiring;
13 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\ReflectionBasedAutowiring;
14 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\SourceCache;
15 use WPMU_DEV\Defender\Vendor\DI\Definition\Source\SourceChain;
16 use WPMU_DEV\Defender\Vendor\DI\Proxy\ProxyFactory;
17 use InvalidArgumentException;
18 use WPMU_DEV\Defender\Vendor\Psr\Container\ContainerInterface;
19
20 /**
21 * Helper to create and configure a Container.
22 *
23 * With the default options, the container created is appropriate for the development environment.
24 *
25 * Example:
26 *
27 * $builder = new ContainerBuilder();
28 * $container = $builder->build();
29 *
30 * @api
31 *
32 * @since 3.2
33 * @author Matthieu Napoli <[email protected]>
34 */
35 class ContainerBuilder
36 {
37 /**
38 * Name of the container class, used to create the container.
39 * @var string
40 */
41 private $containerClass;
42
43 /**
44 * Name of the container parent class, used on compiled container.
45 * @var string
46 */
47 private $containerParentClass;
48
49 /**
50 * @var bool
51 */
52 private $useAutowiring = true;
53
54 /**
55 * @var bool
56 */
57 private $useAnnotations = false;
58
59 /**
60 * @var bool
61 */
62 private $ignorePhpDocErrors = false;
63
64 /**
65 * If true, write the proxies to disk to improve performances.
66 * @var bool
67 */
68 private $writeProxiesToFile = false;
69
70 /**
71 * Directory where to write the proxies (if $writeProxiesToFile is enabled).
72 * @var string|null
73 */
74 private $proxyDirectory;
75
76 /**
77 * If PHP-WPMU_DEV\Defender\Vendor\DI is wrapped in another container, this references the wrapper.
78 * @var ContainerInterface
79 */
80 private $wrapperContainer;
81
82 /**
83 * @var DefinitionSource[]|string[]|array[]
84 */
85 private $definitionSources = [];
86
87 /**
88 * Whether the container has already been built.
89 * @var bool
90 */
91 private $locked = false;
92
93 /**
94 * @var string|null
95 */
96 private $compileToDirectory;
97
98 /**
99 * @var bool
100 */
101 private $sourceCache = false;
102
103 /**
104 * @var string
105 */
106 protected $sourceCacheNamespace;
107
108 /**
109 * Build a container configured for the dev environment.
110 */
111 public static function buildDevContainer() : Container
112 {
113 return new Container;
114 }
115
116 /**
117 * @param string $containerClass Name of the container class, used to create the container.
118 */
119 public function __construct(string $containerClass = Container::class)
120 {
121 $this->containerClass = $containerClass;
122 }
123
124 /**
125 * Build and return a container.
126 *
127 * @return Container
128 */
129 public function build()
130 {
131 $sources = array_reverse($this->definitionSources);
132
133 if ($this->useAnnotations) {
134 $autowiring = new AnnotationBasedAutowiring($this->ignorePhpDocErrors);
135 $sources[] = $autowiring;
136 } elseif ($this->useAutowiring) {
137 $autowiring = new ReflectionBasedAutowiring;
138 $sources[] = $autowiring;
139 } else {
140 $autowiring = new NoAutowiring;
141 }
142
143 $sources = array_map(function ($definitions) use ($autowiring) {
144 if (is_string($definitions)) {
145 // File
146 return new DefinitionFile($definitions, $autowiring);
147 } elseif (is_array($definitions)) {
148 return new DefinitionArray($definitions, $autowiring);
149 }
150
151 return $definitions;
152 }, $sources);
153 $source = new SourceChain($sources);
154
155 // Mutable definition source
156 $source->setMutableDefinitionSource(new DefinitionArray([], $autowiring));
157
158 if ($this->sourceCache) {
159 if (!SourceCache::isSupported()) {
160 throw new \Exception('APCu is not enabled, PHP-WPMU_DEV\Defender\Vendor\DI cannot use it as a cache');
161 }
162 // Wrap the source with the cache decorator
163 $source = new SourceCache($source, $this->sourceCacheNamespace);
164 }
165
166 $proxyFactory = new ProxyFactory(
167 $this->writeProxiesToFile,
168 $this->proxyDirectory
169 );
170
171 $this->locked = true;
172
173 $containerClass = $this->containerClass;
174
175 if ($this->compileToDirectory) {
176 $compiler = new Compiler($proxyFactory);
177 $compiledContainerFile = $compiler->compile(
178 $source,
179 $this->compileToDirectory,
180 $containerClass,
181 $this->containerParentClass,
182 $this->useAutowiring || $this->useAnnotations
183 );
184 // Only load the file if it hasn't been already loaded
185 // (the container can be created multiple times in the same process)
186 if (!class_exists($containerClass, false)) {
187 require $compiledContainerFile;
188 }
189 }
190
191 return new $containerClass($source, $proxyFactory, $this->wrapperContainer);
192 }
193
194 /**
195 * Compile the container for optimum performances.
196 *
197 * Be aware that the container is compiled once and never updated!
198 *
199 * Therefore:
200 *
201 * - in production you should clear that directory every time you deploy
202 * - in development you should not compile the container
203 *
204 * @see https://php-di.org/doc/performances.html
205 *
206 * @param string $directory Directory in which to put the compiled container.
207 * @param string $containerClass Name of the compiled class. Customize only if necessary.
208 * @param string $containerParentClass Name of the compiled container parent class. Customize only if necessary.
209 */
210 public function enableCompilation(
211 string $directory,
212 string $containerClass = 'CompiledContainer',
213 string $containerParentClass = CompiledContainer::class
214 ) : self {
215 $this->ensureNotLocked();
216
217 $this->compileToDirectory = $directory;
218 $this->containerClass = $containerClass;
219 $this->containerParentClass = $containerParentClass;
220
221 return $this;
222 }
223
224 /**
225 * Enable or disable the use of autowiring to guess injections.
226 *
227 * Enabled by default.
228 *
229 * @return $this
230 */
231 public function useAutowiring(bool $bool) : self
232 {
233 $this->ensureNotLocked();
234
235 $this->useAutowiring = $bool;
236
237 return $this;
238 }
239
240 /**
241 * Enable or disable the use of annotations to guess injections.
242 *
243 * Disabled by default.
244 *
245 * @return $this
246 */
247 public function useAnnotations(bool $bool) : self
248 {
249 $this->ensureNotLocked();
250
251 $this->useAnnotations = $bool;
252
253 return $this;
254 }
255
256 /**
257 * Enable or disable ignoring phpdoc errors (non-existent classes in `@param` or `@var`).
258 *
259 * @return $this
260 */
261 public function ignorePhpDocErrors(bool $bool) : self
262 {
263 $this->ensureNotLocked();
264
265 $this->ignorePhpDocErrors = $bool;
266
267 return $this;
268 }
269
270 /**
271 * Configure the proxy generation.
272 *
273 * For dev environment, use `writeProxiesToFile(false)` (default configuration)
274 * For production environment, use `writeProxiesToFile(true, 'tmp/proxies')`
275 *
276 * @see https://php-di.org/doc/lazy-injection.html
277 *
278 * @param bool $writeToFile If true, write the proxies to disk to improve performances
279 * @param string|null $proxyDirectory Directory where to write the proxies
280 * @throws InvalidArgumentException when writeToFile is set to true and the proxy directory is null
281 * @return $this
282 */
283 public function writeProxiesToFile(bool $writeToFile, string $proxyDirectory = null) : self
284 {
285 $this->ensureNotLocked();
286
287 $this->writeProxiesToFile = $writeToFile;
288
289 if ($writeToFile && $proxyDirectory === null) {
290 throw new InvalidArgumentException(
291 'The proxy directory must be specified if you want to write proxies on disk'
292 );
293 }
294 $this->proxyDirectory = $proxyDirectory;
295
296 return $this;
297 }
298
299 /**
300 * If PHP-DI's container is wrapped by another container, we can
301 * set this so that PHP-WPMU_DEV\Defender\Vendor\DI will use the wrapper rather than itself for building objects.
302 *
303 * @return $this
304 */
305 public function wrapContainer(ContainerInterface $otherContainer) : self
306 {
307 $this->ensureNotLocked();
308
309 $this->wrapperContainer = $otherContainer;
310
311 return $this;
312 }
313
314 /**
315 * Add definitions to the container.
316 *
317 * @param string|array|DefinitionSource ...$definitions Can be an array of definitions, the
318 * name of a file containing definitions
319 * or a DefinitionSource object.
320 * @return $this
321 */
322 public function addDefinitions(...$definitions) : self
323 {
324 $this->ensureNotLocked();
325
326 foreach ($definitions as $definition) {
327 if (!is_string($definition) && !is_array($definition) && !($definition instanceof DefinitionSource)) {
328 throw new InvalidArgumentException(sprintf(
329 '%s parameter must be a string, an array or a DefinitionSource object, %s given',
330 'ContainerBuilder::addDefinitions()',
331 is_object($definition) ? get_class($definition) : gettype($definition)
332 ));
333 }
334
335 $this->definitionSources[] = $definition;
336 }
337
338 return $this;
339 }
340
341 /**
342 * Enables the use of APCu to cache definitions.
343 *
344 * You must have APCu enabled to use it.
345 *
346 * Before using this feature, you should try these steps first:
347 * - enable compilation if not already done (see `enableCompilation()`)
348 * - if you use autowiring or annotations, add all the classes you are using into your configuration so that
349 * PHP-WPMU_DEV\Defender\Vendor\DI knows about them and compiles them
350 * Once this is done, you can try to optimize performances further with APCu. It can also be useful if you use
351 * `Container::make()` instead of `get()` (`make()` calls cannot be compiled so they are not optimized).
352 *
353 * Remember to clear APCu on each deploy else your application will have a stale cache. Do not enable the cache
354 * in development environment: any change you will make to the code will be ignored because of the cache.
355 *
356 * @see https://php-di.org/doc/performances.html
357 *
358 * @param string $cacheNamespace use unique namespace per container when sharing a single APC memory pool to prevent cache collisions
359 * @return $this
360 */
361 public function enableDefinitionCache(string $cacheNamespace = '') : self
362 {
363 $this->ensureNotLocked();
364
365 $this->sourceCache = true;
366 $this->sourceCacheNamespace = $cacheNamespace;
367
368 return $this;
369 }
370
371 /**
372 * Are we building a compiled container?
373 */
374 public function isCompilationEnabled() : bool
375 {
376 return (bool) $this->compileToDirectory;
377 }
378
379 private function ensureNotLocked()
380 {
381 if ($this->locked) {
382 throw new \LogicException('The ContainerBuilder cannot be modified after the container has been built');
383 }
384 }
385 }
386