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