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