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