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