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