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($on = TRUE)
59: {
60: $this->parameters['productionMode'] = (bool) $on;
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: 'consoleMode' => PHP_SAPI === 'cli',
114: 'container' => array(
115: 'class' => 'SystemContainer',
116: 'parent' => 'Nette\DI\Container',
117: )
118: );
119: }
120:
121:
122:
123: 124: 125:
126: public function createRobotLoader()
127: {
128: if (!($cacheDir = $this->getCacheDirectory())) {
129: throw new Nette\InvalidStateException("Set path to temporary directory using setTempDirectory().");
130: }
131: $loader = new Nette\Loaders\RobotLoader;
132: $loader->setCacheStorage(new Nette\Caching\Storages\FileStorage($cacheDir));
133: $loader->autoRebuild = !$this->parameters['productionMode'];
134: return $loader;
135: }
136:
137:
138:
139: 140: 141: 142:
143: public function addConfig($file, $section = self::AUTO)
144: {
145: if ($section === self::AUTO) {
146: $section = $this->parameters['productionMode'] ? self::PRODUCTION : self::DEVELOPMENT;
147: }
148: $this->files[] = array($file, $section);
149: return $this;
150: }
151:
152:
153:
154:
155: public function loadConfig($file, $section = NULL)
156: {
157: trigger_error(__METHOD__ . '() is deprecated; use addConfig(file, [section])->createContainer() instead.', E_USER_WARNING);
158: return $this->addConfig($file, $section)->createContainer();
159: }
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 => $this->parameters['productionMode'] ? NULL : $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:
201: protected function buildContainer(& $dependencies = NULL)
202: {
203: $loader = $this->createLoader();
204: $config = array();
205: $code = "<?php\n";
206: foreach ($this->files as $tmp) {
207: list($file, $section) = $tmp;
208: $config = Helpers::merge($loader->load($file, $section), $config);
209: $code .= "// source: $file $section\n";
210: }
211: $code .= "\n";
212:
213: $this->checkCompatibility($config);
214:
215: if (!isset($config['parameters'])) {
216: $config['parameters'] = array();
217: }
218: $config['parameters'] = Helpers::merge($config['parameters'], $this->parameters);
219:
220: $compiler = $this->createCompiler();
221: $this->onCompile($this, $compiler);
222:
223: $code .= $compiler->compile(
224: $config,
225: $this->parameters['container']['class'],
226: $config['parameters']['container']['parent']
227: );
228: $dependencies = array_merge($loader->getDependencies(), $compiler->getContainerBuilder()->getDependencies());
229: return $code;
230: }
231:
232:
233:
234: protected function checkCompatibility(array $config)
235: {
236: foreach (array('service' => 'services', 'variable' => 'parameters', 'variables' => 'parameters', 'mode' => 'parameters', 'const' => 'constants') as $old => $new) {
237: if (isset($config[$old])) {
238: throw new Nette\DeprecatedException("Section '$old' in configuration file is deprecated; use '$new' instead.");
239: }
240: }
241: if (isset($config['services'])) {
242: foreach ($config['services'] as $key => $def) {
243: foreach (array('option' => 'arguments', 'methods' => 'setup') as $old => $new) {
244: if (is_array($def) && isset($def[$old])) {
245: throw new Nette\DeprecatedException("Section '$old' in service definition is deprecated; refactor it into '$new'.");
246: }
247: }
248: }
249: }
250: }
251:
252:
253:
254: 255: 256:
257: protected function createCompiler()
258: {
259: $compiler = new Compiler;
260: $compiler->addExtension('php', new Extensions\PhpExtension)
261: ->addExtension('constants', new Extensions\ConstantsExtension)
262: ->addExtension('nette', new Extensions\NetteExtension);
263: return $compiler;
264: }
265:
266:
267:
268: 269: 270:
271: protected function createLoader()
272: {
273: return new Loader;
274: }
275:
276:
277:
278: protected function getCacheDirectory()
279: {
280: return empty($this->parameters['tempDir']) ? NULL : $this->parameters['tempDir'] . '/cache';
281: }
282:
283:
284:
285:
286:
287:
288:
289: 290: 291: 292:
293: public static function detectProductionMode()
294: {
295: return !isset($_SERVER['REMOTE_ADDR']) || !in_array($_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'), TRUE);
296: }
297:
298: }
299: