• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / bootstrap / 3696152907

pending completion
3696152907

push

github

David Grudl
PhpExtension: supports dynamic parameters

2 of 2 new or added lines in 1 file covered. (100.0%)

124 of 143 relevant lines covered (86.71%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.6
/src/Bootstrap/Configurator.php
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

8
declare(strict_types=1);
9

10
namespace Nette\Bootstrap;
11

12
use Composer\Autoload\ClassLoader;
13
use Latte;
14
use Nette;
15
use Nette\DI;
16
use Tracy;
17

18

19
/**
20
 * Initial system DI container generator.
21
 */
22
class Configurator
23
{
24
        use Nette\SmartObject;
25

26
        public const CookieSecret = 'nette-debug';
27

28
        /** @deprecated  use Configurator::CookieSecret */
29
        public const COOKIE_SECRET = self::CookieSecret;
30

31

32
        /** @var callable[]  function (Configurator $sender, DI\Compiler $compiler); Occurs after the compiler is created */
33
        public $onCompile = [];
34

35
        /** @var array */
36
        public $defaultExtensions = [
37
                'application' => [Nette\Bridges\ApplicationDI\ApplicationExtension::class, ['%debugMode%', ['%appDir%'], '%tempDir%/cache/nette.application']],
38
                'cache' => [Nette\Bridges\CacheDI\CacheExtension::class, ['%tempDir%']],
39
                'constants' => Extensions\ConstantsExtension::class,
40
                'database' => [Nette\Bridges\DatabaseDI\DatabaseExtension::class, ['%debugMode%']],
41
                'decorator' => Nette\DI\Extensions\DecoratorExtension::class,
42
                'di' => [Nette\DI\Extensions\DIExtension::class, ['%debugMode%']],
43
                'extensions' => Nette\DI\Extensions\ExtensionsExtension::class,
44
                'forms' => Nette\Bridges\FormsDI\FormsExtension::class,
45
                'http' => [Nette\Bridges\HttpDI\HttpExtension::class, ['%consoleMode%']],
46
                'inject' => Nette\DI\Extensions\InjectExtension::class,
47
                'latte' => [Nette\Bridges\ApplicationDI\LatteExtension::class, ['%tempDir%/cache/latte', '%debugMode%']],
48
                'mail' => Nette\Bridges\MailDI\MailExtension::class,
49
                'php' => Extensions\PhpExtension::class,
50
                'routing' => [Nette\Bridges\ApplicationDI\RoutingExtension::class, ['%debugMode%']],
51
                'search' => [Nette\DI\Extensions\SearchExtension::class, ['%tempDir%/cache/nette.search']],
52
                'security' => [Nette\Bridges\SecurityDI\SecurityExtension::class, ['%debugMode%']],
53
                'session' => [Nette\Bridges\HttpDI\SessionExtension::class, ['%debugMode%', '%consoleMode%']],
54
                'tracy' => [Tracy\Bridges\Nette\TracyExtension::class, ['%debugMode%', '%consoleMode%']],
55
        ];
56

57
        /** @var string[] of classes which shouldn't be autowired */
58
        public $autowireExcludedClasses = [
59
                \ArrayAccess::class,
60
                \Countable::class,
61
                \IteratorAggregate::class,
62
                \stdClass::class,
63
                \Traversable::class,
64
        ];
65

66
        /** @var array */
67
        protected $staticParameters;
68

69
        /** @var array */
70
        protected $dynamicParameters = [];
71

72
        /** @var array */
73
        protected $services = [];
74

75
        /** @var array of string|array */
76
        protected $configs = [];
77

78

79
        public function __construct()
80
        {
81
                $this->staticParameters = $this->getDefaultParameters();
1✔
82
        }
1✔
83

84

85
        /**
86
         * Set parameter %debugMode%.
87
         * @param  bool|string|array  $value
88
         * @return static
89
         */
90
        public function setDebugMode($value)
91
        {
92
                if (is_string($value) || is_array($value)) {
1✔
93
                        $value = static::detectDebugMode($value);
1✔
94
                } elseif (!is_bool($value)) {
1✔
95
                        throw new Nette\InvalidArgumentException(sprintf('Value must be either a string, array, or boolean, %s given.', gettype($value)));
1✔
96
                }
97

98
                $this->staticParameters['debugMode'] = $value;
1✔
99
                $this->staticParameters['productionMode'] = !$this->staticParameters['debugMode']; // compatibility
1✔
100
                return $this;
1✔
101
        }
102

103

104
        public function isDebugMode(): bool
105
        {
106
                return $this->staticParameters['debugMode'];
1✔
107
        }
108

109

110
        /**
111
         * Sets path to temporary directory.
112
         * @return static
113
         */
114
        public function setTempDirectory(string $path)
1✔
115
        {
116
                $this->staticParameters['tempDir'] = $path;
1✔
117
                return $this;
1✔
118
        }
119

120

121
        /**
122
         * Sets the default timezone.
123
         * @return static
124
         */
125
        public function setTimeZone(string $timezone)
1✔
126
        {
127
                date_default_timezone_set($timezone);
1✔
128
                @ini_set('date.timezone', $timezone); // @ - function may be disabled
1✔
129
                return $this;
1✔
130
        }
131

132

133
        /**
134
         * Alias for addStaticParameters()
135
         * @return static
136
         */
137
        public function addParameters(array $params)
1✔
138
        {
139
                return $this->addStaticParameters($params);
1✔
140
        }
141

142

143
        /**
144
         * Adds new static parameters.
145
         * @return static
146
         */
147
        public function addStaticParameters(array $params)
1✔
148
        {
149
                $this->staticParameters = DI\Config\Helpers::merge($params, $this->staticParameters);
1✔
150
                return $this;
1✔
151
        }
152

153

154
        /**
155
         * Adds new dynamic parameters.
156
         * @return static
157
         */
158
        public function addDynamicParameters(array $params)
1✔
159
        {
160
                $this->dynamicParameters = $params + $this->dynamicParameters;
1✔
161
                return $this;
1✔
162
        }
163

164

165
        /**
166
         * Add instances of services.
167
         * @return static
168
         */
169
        public function addServices(array $services)
1✔
170
        {
171
                $this->services = $services + $this->services;
1✔
172
                return $this;
1✔
173
        }
174

175

176
        protected function getDefaultParameters(): array
177
        {
178
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
1✔
179
                $last = end($trace);
1✔
180
                $debugMode = static::detectDebugMode();
1✔
181
                $loaderRc = class_exists(ClassLoader::class)
1✔
182
                        ? new \ReflectionClass(ClassLoader::class)
1✔
183
                        : null;
1✔
184
                return [
185
                        'appDir' => isset($trace[1]['file']) ? dirname($trace[1]['file']) : null,
1✔
186
                        'wwwDir' => isset($last['file']) ? dirname($last['file']) : null,
1✔
187
                        'vendorDir' => $loaderRc ? dirname($loaderRc->getFileName(), 2) : null,
1✔
188
                        'debugMode' => $debugMode,
1✔
189
                        'productionMode' => !$debugMode,
1✔
190
                        'consoleMode' => PHP_SAPI === 'cli',
1✔
191
                ];
192
        }
193

194

195
        public function enableTracy(?string $logDirectory = null, ?string $email = null): void
196
        {
197
                if (!class_exists(Tracy\Debugger::class)) {
×
198
                        throw new Nette\NotSupportedException('Tracy not found, do you have `tracy/tracy` package installed?');
×
199
                }
200

201
                Tracy\Debugger::$strictMode = true;
×
202
                Tracy\Debugger::enable(!$this->staticParameters['debugMode'], $logDirectory, $email);
×
203
                Tracy\Bridges\Nette\Bridge::initialize();
×
204
                if (class_exists(Latte\Bridges\Tracy\BlueScreenPanel::class)) {
×
205
                        Latte\Bridges\Tracy\BlueScreenPanel::initialize();
×
206
                }
207
        }
208

209

210
        /**
211
         * Alias for enableTracy()
212
         */
213
        public function enableDebugger(?string $logDirectory = null, ?string $email = null): void
214
        {
215
                $this->enableTracy($logDirectory, $email);
×
216
        }
217

218

219
        /**
220
         * @throws Nette\NotSupportedException if RobotLoader is not available
221
         */
222
        public function createRobotLoader(): Nette\Loaders\RobotLoader
223
        {
224
                if (!class_exists(Nette\Loaders\RobotLoader::class)) {
1✔
225
                        throw new Nette\NotSupportedException('RobotLoader not found, do you have `nette/robot-loader` package installed?');
×
226
                }
227

228
                $loader = new Nette\Loaders\RobotLoader;
1✔
229
                $loader->setTempDirectory($this->getCacheDirectory() . '/nette.robotLoader');
1✔
230
                $loader->setAutoRefresh($this->staticParameters['debugMode']);
1✔
231

232
                if (isset($this->defaultExtensions['application'])) {
1✔
233
                        $this->defaultExtensions['application'][1][1] = null;
1✔
234
                        $this->defaultExtensions['application'][1][3] = $loader;
1✔
235
                }
236

237
                return $loader;
1✔
238
        }
239

240

241
        /**
242
         * Adds configuration file.
243
         * @param  string|array  $config
244
         * @return static
245
         */
246
        public function addConfig($config)
247
        {
248
                $this->configs[] = $config;
1✔
249
                return $this;
1✔
250
        }
251

252

253
        /**
254
         * Returns system DI container.
255
         */
256
        public function createContainer(bool $initialize = true): DI\Container
1✔
257
        {
258
                $class = $this->loadContainer();
1✔
259
                $container = new $class($this->dynamicParameters);
1✔
260
                foreach ($this->services as $name => $service) {
1✔
261
                        $container->addService($name, $service);
1✔
262
                }
263

264
                if ($initialize) {
1✔
265
                        $container->initialize();
1✔
266
                }
267

268
                return $container;
1✔
269
        }
270

271

272
        /**
273
         * Loads system DI container class and returns its name.
274
         */
275
        public function loadContainer(): string
276
        {
277
                $loader = new DI\ContainerLoader(
1✔
278
                        $this->getCacheDirectory() . '/nette.configurator',
1✔
279
                        $this->staticParameters['debugMode']
1✔
280
                );
281
                return $loader->load(
1✔
282
                        [$this, 'generateContainer'],
1✔
283
                        $this->generateContainerKey(),
1✔
284
                );
285
        }
286

287

288
        /**
289
         * @internal
290
         */
291
        public function generateContainer(DI\Compiler $compiler): void
1✔
292
        {
293
                $loader = $this->createLoader();
1✔
294
                $loader->setParameters($this->staticParameters);
1✔
295

296
                foreach ($this->configs as $config) {
1✔
297
                        if (is_string($config)) {
1✔
298
                                $compiler->loadConfig($config, $loader);
1✔
299
                        } else {
300
                                $compiler->addConfig($config);
×
301
                        }
302
                }
303

304
                $compiler->addConfig(['parameters' => DI\Helpers::escape($this->staticParameters)]);
1✔
305
                $compiler->setDynamicParameterNames(array_keys($this->dynamicParameters));
1✔
306

307
                $builder = $compiler->getContainerBuilder();
1✔
308
                $builder->addExcludedClasses($this->autowireExcludedClasses);
1✔
309

310
                foreach ($this->defaultExtensions as $name => $extension) {
1✔
311
                        [$class, $args] = is_string($extension)
1✔
312
                                ? [$extension, []]
1✔
313
                                : $extension;
1✔
314
                        if (class_exists($class)) {
1✔
315
                                $args = DI\Helpers::expand($args, $this->staticParameters);
1✔
316
                                $compiler->addExtension($name, (new \ReflectionClass($class))->newInstanceArgs($args));
1✔
317
                        }
318
                }
319

320
                Nette\Utils\Arrays::invoke($this->onCompile, $this, $compiler);
1✔
321
        }
1✔
322

323

324
        protected function createLoader(): DI\Config\Loader
325
        {
326
                return new DI\Config\Loader;
1✔
327
        }
328

329

330
        protected function generateContainerKey(): array
331
        {
332
                return [
333
                        $this->staticParameters,
1✔
334
                        array_keys($this->dynamicParameters),
1✔
335
                        $this->configs,
1✔
336
                        PHP_VERSION_ID - PHP_RELEASE_VERSION, // minor PHP version
1✔
337
                        class_exists(ClassLoader::class) // composer update
1✔
338
                                ? filemtime((new \ReflectionClass(ClassLoader::class))->getFilename())
1✔
339
                                : null,
340
                ];
341
        }
342

343

344
        protected function getCacheDirectory(): string
345
        {
346
                if (empty($this->staticParameters['tempDir'])) {
1✔
347
                        throw new Nette\InvalidStateException('Set path to temporary directory using setTempDirectory().');
1✔
348
                }
349

350
                $dir = $this->staticParameters['tempDir'] . '/cache';
1✔
351
                Nette\Utils\FileSystem::createDir($dir);
1✔
352
                return $dir;
1✔
353
        }
354

355

356
        /********************* tools ****************d*g**/
357

358

359
        /**
360
         * Detects debug mode by IP addresses or computer names whitelist detection.
361
         * @param  string|array  $list
362
         */
363
        public static function detectDebugMode($list = null): bool
1✔
364
        {
365
                $addr = $_SERVER['REMOTE_ADDR'] ?? php_uname('n');
1✔
366
                $secret = is_string($_COOKIE[self::CookieSecret] ?? null)
1✔
367
                        ? $_COOKIE[self::CookieSecret]
1✔
368
                        : null;
1✔
369
                $list = is_string($list)
1✔
370
                        ? preg_split('#[,\s]+#', $list)
1✔
371
                        : (array) $list;
1✔
372
                if (!isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !isset($_SERVER['HTTP_FORWARDED'])) {
1✔
373
                        $list[] = '127.0.0.1';
1✔
374
                        $list[] = '::1';
1✔
375
                        $list[] = '[::1]'; // workaround for PHP < 7.3.4
1✔
376
                }
377

378
                return in_array($addr, $list, true) || in_array("$secret@$addr", $list, true);
1✔
379
        }
380
}
381

382

383
class_exists(Nette\Configurator::class);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc