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