1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Config\Extensions;
9:
10: use Nette,
11: Nette\DI\ContainerBuilder,
12: Nette\Utils\Validators;
13:
14:
15: 16: 17: 18: 19:
20: class NetteExtension extends Nette\Config\CompilerExtension
21: {
22: public $defaults = array(
23: 'xhtml' => TRUE,
24: 'session' => array(
25: 'iAmUsingBadHost' => NULL,
26: 'autoStart' => 'smart',
27: 'expiration' => NULL,
28: ),
29: 'application' => array(
30: 'debugger' => TRUE,
31: 'errorPresenter' => NULL,
32: 'catchExceptions' => '%productionMode%',
33: ),
34: 'routing' => array(
35: 'debugger' => TRUE,
36: 'routes' => array(),
37: ),
38: 'security' => array(
39: 'debugger' => TRUE,
40: 'frames' => 'SAMEORIGIN',
41: 'users' => array(),
42: 'roles' => array(),
43: 'resources' => array(),
44: ),
45: 'mailer' => array(
46: 'smtp' => FALSE,
47: ),
48: 'database' => array(),
49: 'forms' => array(
50: 'messages' => array(),
51: ),
52: 'container' => array(
53: 'debugger' => FALSE,
54: ),
55: 'debugger' => array(
56: 'email' => NULL,
57: 'editor' => NULL,
58: 'browser' => NULL,
59: 'strictMode' => NULL,
60: 'bar' => array(),
61: 'blueScreen' => array(),
62: ),
63: );
64:
65: public $databaseDefaults = array(
66: 'dsn' => NULL,
67: 'user' => NULL,
68: 'password' => NULL,
69: 'options' => NULL,
70: 'debugger' => TRUE,
71: 'explain' => TRUE,
72: 'reflection' => 'Nette\Database\Reflection\DiscoveredReflection',
73: );
74:
75:
76: public function loadConfiguration()
77: {
78: $container = $this->getContainerBuilder();
79: $config = $this->getConfig($this->defaults);
80:
81:
82:
83: $container->addDefinition($this->prefix('cacheJournal'))
84: ->setClass('Nette\Caching\Storages\FileJournal', array('%tempDir%'));
85:
86: $container->addDefinition('cacheStorage')
87: ->setClass('Nette\Caching\Storages\FileStorage', array('%tempDir%/cache'));
88:
89: $container->addDefinition($this->prefix('templateCacheStorage'))
90: ->setClass('Nette\Caching\Storages\PhpFileStorage', array('%tempDir%/cache'))
91: ->setAutowired(FALSE);
92:
93: $container->addDefinition($this->prefix('cache'))
94: ->setClass('Nette\Caching\Cache', array(1 => '%namespace%'))
95: ->setParameters(array('namespace' => NULL));
96:
97:
98:
99: $container->addDefinition($this->prefix('httpRequestFactory'))
100: ->setClass('Nette\Http\RequestFactory')
101: ->addSetup('setEncoding', array('UTF-8'))
102: ->setInternal(TRUE);
103:
104: $container->addDefinition('httpRequest')
105: ->setClass('Nette\Http\Request')
106: ->setFactory('@Nette\Http\RequestFactory::createHttpRequest');
107:
108: $container->addDefinition('httpResponse')
109: ->setClass('Nette\Http\Response');
110:
111: $container->addDefinition($this->prefix('httpContext'))
112: ->setClass('Nette\Http\Context');
113:
114:
115:
116: $session = $container->addDefinition('session')
117: ->setClass('Nette\Http\Session');
118:
119: if (isset($config['session']['expiration'])) {
120: $session->addSetup('setExpiration', array($config['session']['expiration']));
121: }
122: if (isset($config['session']['iAmUsingBadHost'])) {
123: $session->addSetup('Nette\Framework::$iAmUsingBadHost = ?;', array((bool) $config['session']['iAmUsingBadHost']));
124: }
125: unset($config['session']['expiration'], $config['session']['autoStart'], $config['session']['iAmUsingBadHost']);
126: if (!empty($config['session'])) {
127: $session->addSetup('setOptions', array($config['session']));
128: }
129:
130:
131:
132: $container->addDefinition($this->prefix('userStorage'))
133: ->setClass('Nette\Http\UserStorage');
134:
135: $user = $container->addDefinition('user')
136: ->setClass('Nette\Security\User');
137:
138: if (!$container->parameters['productionMode'] && $config['security']['debugger']) {
139: $user->addSetup('Nette\Diagnostics\Debugger::$bar->addPanel(?)', array(
140: new Nette\DI\Statement('Nette\Security\Diagnostics\UserPanel')
141: ));
142: }
143:
144: if ($config['security']['users']) {
145: $container->addDefinition($this->prefix('authenticator'))
146: ->setClass('Nette\Security\SimpleAuthenticator', array($config['security']['users']));
147: }
148:
149: if ($config['security']['roles'] || $config['security']['resources']) {
150: $authorizator = $container->addDefinition($this->prefix('authorizator'))
151: ->setClass('Nette\Security\Permission');
152: foreach ($config['security']['roles'] as $role => $parents) {
153: $authorizator->addSetup('addRole', array($role, $parents));
154: }
155: foreach ($config['security']['resources'] as $resource => $parents) {
156: $authorizator->addSetup('addResource', array($resource, $parents));
157: }
158: }
159:
160:
161:
162: $application = $container->addDefinition('application')
163: ->setClass('Nette\Application\Application')
164: ->addSetup('$catchExceptions', $config['application']['catchExceptions'])
165: ->addSetup('$errorPresenter', $config['application']['errorPresenter']);
166:
167: if ($config['application']['debugger']) {
168: $application->addSetup('Nette\Application\Diagnostics\RoutingPanel::initializePanel');
169: }
170:
171: $container->addDefinition($this->prefix('presenterFactory'))
172: ->setClass('Nette\Application\PresenterFactory', array(
173: isset($container->parameters['appDir']) ? $container->parameters['appDir'] : NULL
174: ));
175:
176:
177:
178: $router = $container->addDefinition('router')
179: ->setClass('Nette\Application\Routers\RouteList');
180:
181: foreach ($config['routing']['routes'] as $mask => $action) {
182: $router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?);', array($mask, $action));
183: }
184:
185: if (!$container->parameters['productionMode'] && $config['routing']['debugger']) {
186: $application->addSetup('Nette\Diagnostics\Debugger::$bar->addPanel(?)', array(
187: new Nette\DI\Statement('Nette\Application\Diagnostics\RoutingPanel')
188: ));
189: }
190:
191:
192:
193: if (empty($config['mailer']['smtp'])) {
194: $container->addDefinition($this->prefix('mailer'))
195: ->setClass('Nette\Mail\SendmailMailer');
196: } else {
197: $container->addDefinition($this->prefix('mailer'))
198: ->setClass('Nette\Mail\SmtpMailer', array($config['mailer']));
199: }
200:
201: $container->addDefinition($this->prefix('mail'))
202: ->setClass('Nette\Mail\Message')
203: ->addSetup('setMailer')
204: ->setShared(FALSE);
205:
206:
207:
208: $container->addDefinition($this->prefix('basicForm'))
209: ->setClass('Nette\Forms\Form')
210: ->setShared(FALSE);
211:
212:
213:
214: $latte = $container->addDefinition($this->prefix('latte'))
215: ->setClass('Nette\Latte\Engine')
216: ->setShared(FALSE);
217:
218: if (empty($config['xhtml'])) {
219: $latte->addSetup('$service->getCompiler()->defaultContentType = ?', Nette\Latte\Compiler::CONTENT_HTML);
220: }
221:
222: $container->addDefinition($this->prefix('template'))
223: ->setClass('Nette\Templating\FileTemplate')
224: ->addSetup('registerFilter', array($latte))
225: ->addSetup('registerHelperLoader', array('Nette\Templating\Helpers::loader'))
226: ->setShared(FALSE);
227:
228:
229:
230: $container->addDefinition($this->prefix('database'))
231: ->setClass('Nette\DI\NestedAccessor', array('@container', $this->prefix('database')));
232:
233: if (isset($config['database']['dsn'])) {
234: $config['database'] = array('default' => $config['database']);
235: }
236:
237: $autowired = TRUE;
238: foreach ((array) $config['database'] as $name => $info) {
239: if (!is_array($info)) {
240: continue;
241: }
242: $info += $this->databaseDefaults + array('autowired' => $autowired);
243: $autowired = FALSE;
244:
245: foreach ((array) $info['options'] as $key => $value) {
246: if (preg_match('#^PDO::\w+\z#', $key)) {
247: unset($info['options'][$key]);
248: $info['options'][constant($key)] = $value;
249: }
250: }
251:
252: $connection = $container->addDefinition($this->prefix("database.$name"))
253: ->setClass('Nette\Database\Connection', array($info['dsn'], $info['user'], $info['password'], $info['options']))
254: ->setAutowired($info['autowired'])
255: ->addSetup('setCacheStorage')
256: ->addSetup('Nette\Diagnostics\Debugger::$blueScreen->addPanel(?)', array(
257: 'Nette\Database\Diagnostics\ConnectionPanel::renderException'
258: ));
259:
260: if ($info['reflection']) {
261: $connection->addSetup('setDatabaseReflection', is_string($info['reflection'])
262: ? array(new Nette\DI\Statement(preg_match('#^[a-z]+\z#', $info['reflection']) ? 'Nette\Database\Reflection\\' . ucfirst($info['reflection']) . 'Reflection' : $info['reflection']))
263: : Nette\Config\Compiler::filterArguments(array($info['reflection']))
264: );
265: }
266:
267: if (!$container->parameters['productionMode'] && $info['debugger']) {
268: $panel = $container->addDefinition($this->prefix("database.{$name}ConnectionPanel"))
269: ->setClass('Nette\Database\Diagnostics\ConnectionPanel')
270: ->setAutowired(FALSE)
271: ->addSetup('$explain', !empty($info['explain']))
272: ->addSetup('$name', $name)
273: ->addSetup('Nette\Diagnostics\Debugger::$bar->addPanel(?)', array('@self'));
274:
275: $connection->addSetup('$service->onQuery[] = ?', array(array($panel, 'logQuery')));
276: }
277: }
278: }
279:
280:
281: public function afterCompile(Nette\Utils\PhpGenerator\ClassType $class)
282: {
283: $initialize = $class->methods['initialize'];
284: $container = $this->getContainerBuilder();
285: $config = $this->getConfig($this->defaults);
286:
287:
288: foreach (array('email', 'editor', 'browser', 'strictMode', 'maxLen', 'maxDepth') as $key) {
289: if (isset($config['debugger'][$key])) {
290: $initialize->addBody('Nette\Diagnostics\Debugger::$? = ?;', array($key, $config['debugger'][$key]));
291: }
292: }
293:
294: if (!$container->parameters['productionMode']) {
295: if ($config['container']['debugger']) {
296: $config['debugger']['bar'][] = 'Nette\DI\Diagnostics\ContainerPanel';
297: }
298:
299: foreach ((array) $config['debugger']['bar'] as $item) {
300: $initialize->addBody($container->formatPhp(
301: 'Nette\Diagnostics\Debugger::$bar->addPanel(?);',
302: Nette\Config\Compiler::filterArguments(array(is_string($item) ? new Nette\DI\Statement($item) : $item))
303: ));
304: }
305: }
306:
307: foreach ((array) $config['debugger']['blueScreen'] as $item) {
308: $initialize->addBody($container->formatPhp(
309: 'Nette\Diagnostics\Debugger::$blueScreen->addPanel(?);',
310: Nette\Config\Compiler::filterArguments(array($item))
311: ));
312: }
313:
314: if (!empty($container->parameters['tempDir'])) {
315: $initialize->addBody($this->checkTempDir($container->expand('%tempDir%/cache')));
316: }
317:
318: foreach ((array) $config['forms']['messages'] as $name => $text) {
319: $initialize->addBody('Nette\Forms\Rules::$defaultMessages[Nette\Forms\Form::?] = ?;', array($name, $text));
320: }
321:
322: if ($config['session']['autoStart'] === 'smart') {
323: $initialize->addBody('$this->getService("session")->exists() && $this->getService("session")->start();');
324: } elseif ($config['session']['autoStart']) {
325: $initialize->addBody('$this->getService("session")->start();');
326: }
327:
328: if (empty($config['xhtml'])) {
329: $initialize->addBody('Nette\Utils\Html::$xhtml = ?;', array((bool) $config['xhtml']));
330: }
331:
332: if (isset($config['security']['frames']) && $config['security']['frames'] !== TRUE) {
333: $frames = $config['security']['frames'];
334: if ($frames === FALSE) {
335: $frames = 'DENY';
336: } elseif (preg_match('#^https?:#', $frames)) {
337: $frames = "ALLOW-FROM $frames";
338: }
339: $initialize->addBody('header(?);', array("X-Frame-Options: $frames"));
340: }
341:
342: foreach ($container->findByTag('run') as $name => $on) {
343: if ($on) {
344: $initialize->addBody('$this->getService(?);', array($name));
345: }
346: }
347: }
348:
349:
350: private function checkTempDir($dir)
351: {
352:
353: $uniq = uniqid('_', TRUE);
354: if (!@mkdir("$dir/$uniq", 0777)) {
355: throw new Nette\InvalidStateException("Unable to write to directory '$dir'. Make this directory writable.");
356: }
357:
358:
359: $useDirs = @file_put_contents("$dir/$uniq/_", '') !== FALSE;
360: @unlink("$dir/$uniq/_");
361: @rmdir("$dir/$uniq");
362:
363: return 'Nette\Caching\Storages\FileStorage::$useDirectories = ' . ($useDirs ? 'TRUE' : 'FALSE') . ";\n";
364: }
365:
366: }
367: