1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Config;
13:
14: use Nette,
15: Nette\Caching\Cache;
16:
17:
18:
19: 20: 21: 22: 23: 24: 25: 26:
27: class Configurator extends Nette\Object
28: {
29:
30: const AUTO = NULL,
31: NONE = FALSE;
32:
33:
34: const DEVELOPMENT = 'development',
35: PRODUCTION = 'production';
36:
37:
38: public $onCompile;
39:
40:
41: protected $parameters;
42:
43:
44: protected $files = array();
45:
46:
47:
48: public function __construct()
49: {
50: $this->parameters = $this->getDefaultParameters();
51: }
52:
53:
54:
55: 56: 57: 58: 59:
60: public function setDebugMode($value = TRUE)
61: {
62: $this->parameters['debugMode'] = is_bool($value) ? $value : static::detectDebugMode($value);
63: $this->parameters['productionMode'] = !$this->parameters['debugMode'];
64: return $this;
65: }
66:
67:
68:
69: 70: 71:
72: public function isDebugMode()
73: {
74: return !$this->parameters['productionMode'];
75: }
76:
77:
78:
79: 80: 81: 82:
83: public function setTempDirectory($path)
84: {
85: $this->parameters['tempDir'] = $path;
86: if (($cacheDir = $this->getCacheDirectory()) && !is_dir($cacheDir)) {
87: mkdir($cacheDir);
88: }
89: return $this;
90: }
91:
92:
93:
94: 95: 96: 97:
98: public function addParameters(array $params)
99: {
100: $this->parameters = Helpers::merge($params, $this->parameters);
101: return $this;
102: }
103:
104:
105:
106: 107: 108:
109: protected function getDefaultParameters()
110: {
111: $trace = debug_backtrace(FALSE);
112: $debugMode = static::detectDebugMode();
113: return array(
114: 'appDir' => isset($trace[1]['file']) ? dirname($trace[1]['file']) : NULL,
115: 'wwwDir' => isset($_SERVER['SCRIPT_FILENAME']) ? dirname($_SERVER['SCRIPT_FILENAME']) : NULL,
116: 'debugMode' => $debugMode,
117: 'productionMode' => !$debugMode,
118: 'environment' => $debugMode ? 'development' : 'production',
119: 'consoleMode' => PHP_SAPI === 'cli',
120: 'container' => array(
121: 'class' => 'SystemContainer',
122: 'parent' => 'Nette\DI\Container',
123: )
124: );
125: }
126:
127:
128:
129: 130: 131: 132: 133:
134: public function enableDebugger($logDirectory = NULL, $email = NULL)
135: {
136: Nette\Diagnostics\Debugger::$strictMode = TRUE;
137: Nette\Diagnostics\Debugger::enable($this->parameters['productionMode'], $logDirectory, $email);
138: }
139:
140:
141:
142: 143: 144:
145: public function createRobotLoader()
146: {
147: if (!($cacheDir = $this->getCacheDirectory())) {
148: throw new Nette\InvalidStateException("Set path to temporary directory using setTempDirectory().");
149: }
150: $loader = new Nette\Loaders\RobotLoader;
151: $loader->setCacheStorage(new Nette\Caching\Storages\FileStorage($cacheDir));
152: $loader->autoRebuild = !$this->parameters['productionMode'];
153: return $loader;
154: }
155:
156:
157:
158: 159: 160: 161:
162: public function addConfig($file, $section = NULL)
163: {
164: $this->files[] = array($file, $section === NULL ? $this->parameters['environment'] : $section);
165: return $this;
166: }
167:
168:
169:
170:
171: public function loadConfig($file, $section = NULL)
172: {
173: trigger_error(__METHOD__ . '() is deprecated; use addConfig(file, [section])->createContainer() instead.', E_USER_WARNING);
174: return $this->addConfig($file, $section)->createContainer();
175: }
176:
177:
178:
179: 180: 181: 182:
183: public function createContainer()
184: {
185: if ($cacheDir = $this->getCacheDirectory()) {
186: $cache = new Cache(new Nette\Caching\Storages\PhpFileStorage($cacheDir), 'Nette.Configurator');
187: $cacheKey = array($this->parameters, $this->files);
188: $cached = $cache->load($cacheKey);
189: if (!$cached) {
190: $code = $this->buildContainer($dependencies);
191: $cache->save($cacheKey, $code, array(
192: Cache::FILES => $dependencies,
193: ));
194: $cached = $cache->load($cacheKey);
195: }
196: Nette\Utils\LimitedScope::load($cached['file'], TRUE);
197:
198: } elseif ($this->files) {
199: throw new Nette\InvalidStateException("Set path to temporary directory using setTempDirectory().");
200:
201: } else {
202: Nette\Utils\LimitedScope::evaluate($this->buildContainer());
203: }
204:
205: $container = new $this->parameters['container']['class'];
206: $container->initialize();
207: Nette\Environment::setContext($container);
208: return $container;
209: }
210:
211:
212:
213: 214: 215: 216:
217: protected function buildContainer(& $dependencies = NULL)
218: {
219: $loader = $this->createLoader();
220: $config = array();
221: $code = "<?php\n";
222: foreach ($this->files as $tmp) {
223: list($file, $section) = $tmp;
224: $config = Helpers::merge($loader->load($file, $section), $config);
225: $code .= "// source: $file $section\n";
226: }
227: $code .= "\n";
228:
229: $this->checkCompatibility($config);
230:
231: if (!isset($config['parameters'])) {
232: $config['parameters'] = array();
233: }
234: $config['parameters'] = Helpers::merge($config['parameters'], $this->parameters);
235:
236: $compiler = $this->createCompiler();
237: $this->onCompile($this, $compiler);
238:
239: $code .= $compiler->compile(
240: $config,
241: $this->parameters['container']['class'],
242: $config['parameters']['container']['parent']
243: );
244: $dependencies = array_merge($loader->getDependencies(), $this->isDebugMode() ? $compiler->getContainerBuilder()->getDependencies() : array());
245: return $code;
246: }
247:
248:
249:
250: protected function checkCompatibility(array $config)
251: {
252: foreach (array('service' => 'services', 'variable' => 'parameters', 'variables' => 'parameters', 'mode' => 'parameters', 'const' => 'constants') as $old => $new) {
253: if (isset($config[$old])) {
254: throw new Nette\DeprecatedException("Section '$old' in configuration file is deprecated; use '$new' instead.");
255: }
256: }
257: if (isset($config['services'])) {
258: foreach ($config['services'] as $key => $def) {
259: foreach (array('option' => 'arguments', 'methods' => 'setup') as $old => $new) {
260: if (is_array($def) && isset($def[$old])) {
261: throw new Nette\DeprecatedException("Section '$old' in service definition is deprecated; refactor it into '$new'.");
262: }
263: }
264: }
265: }
266: }
267:
268:
269:
270: 271: 272:
273: protected function createCompiler()
274: {
275: $compiler = new Compiler;
276: $compiler->addExtension('php', new Extensions\PhpExtension)
277: ->addExtension('constants', new Extensions\ConstantsExtension)
278: ->addExtension('nette', new Extensions\NetteExtension);
279: return $compiler;
280: }
281:
282:
283:
284: 285: 286:
287: protected function createLoader()
288: {
289: return new Loader;
290: }
291:
292:
293:
294: protected function getCacheDirectory()
295: {
296: return empty($this->parameters['tempDir']) ? NULL : $this->parameters['tempDir'] . '/cache';
297: }
298:
299:
300:
301:
302:
303:
304:
305: 306: 307: 308: 309:
310: public static function detectDebugMode($list = NULL)
311: {
312: $list = is_string($list) ? preg_split('#[,\s]+#', $list) : (array) $list;
313: if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
314: $list[] = '127.0.0.1';
315: $list[] = '::1';
316: }
317: return in_array(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : php_uname('n'), $list, TRUE);
318: }
319:
320:
321:
322:
323: public function setProductionMode($value = TRUE)
324: {
325: return $this->setDebugMode(is_bool($value) ? !$value : $value);
326: }
327:
328:
329:
330:
331: public function isProductionMode()
332: {
333: return !$this->isDebugMode();
334: }
335:
336:
337:
338:
339: public static function detectProductionMode($list = NULL)
340: {
341: return !static::detectDebugMode($list);
342: }
343:
344: }
345: