Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationLatte
      • ApplicationTracy
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsLatte
      • Framework
      • HttpTracy
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy

Classes

  • NetteAccessor
  • NetteExtension
  • TracyBridge
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Bridges\Framework;
  9: 
 10: use Nette;
 11: use Nette\DI\ContainerBuilder;
 12: use Nette\Utils\Validators;
 13: use Latte;
 14: 
 15: 
 16: /**
 17:  * Core Nette Framework services.
 18:  *
 19:  * @author     David Grudl
 20:  */
 21: class NetteExtension extends Nette\DI\CompilerExtension
 22: {
 23:     public $defaults = array(
 24:         'http' => array(
 25:             'proxy' => array(),
 26:             'headers' => array(
 27:                 'X-Powered-By' => 'Nette Framework',
 28:                 'Content-Type' => 'text/html; charset=utf-8',
 29:             ),
 30:         ),
 31:         'session' => array(
 32:             'debugger' => FALSE,
 33:             'autoStart' => 'smart', // true|false|smart
 34:             'expiration' => NULL,
 35:         ),
 36:         'application' => array(
 37:             'debugger' => TRUE,
 38:             'errorPresenter' => 'Nette:Error',
 39:             'catchExceptions' => '%productionMode%',
 40:             'mapping' => NULL
 41:         ),
 42:         'routing' => array(
 43:             'debugger' => TRUE,
 44:             'routes' => array(), // of [mask => action]
 45:         ),
 46:         'security' => array(
 47:             'debugger' => TRUE,
 48:             'frames' => 'SAMEORIGIN', // X-Frame-Options
 49:             'users' => array(), // of [user => password] or [user => ['password' => password, 'roles' => [role]]]
 50:             'roles' => array(), // of [role => parents]
 51:             'resources' => array(), // of [resource => parents]
 52:         ),
 53:         'mailer' => array(
 54:             'smtp' => FALSE,
 55:             'host' => NULL,
 56:             'port' => NULL,
 57:             'username' => NULL,
 58:             'password' => NULL,
 59:             'secure' => NULL,
 60:             'timeout' => NULL,
 61:         ),
 62:         'database' => array(), // BC
 63:         'forms' => array(
 64:             'messages' => array(),
 65:         ),
 66:         'latte' => array(
 67:             'xhtml' => FALSE,
 68:             'macros' => array(),
 69:         ),
 70:         'container' => array(
 71:             'debugger' => FALSE,
 72:             'accessors' => TRUE,
 73:         ),
 74:         'debugger' => array(
 75:             'email' => NULL,
 76:             'editor' => NULL,
 77:             'browser' => NULL,
 78:             'strictMode' => NULL,
 79:             'maxLen' => NULL,
 80:             'maxDepth' => NULL,
 81:             'showLocation' => NULL,
 82:             'scream' => NULL,
 83:             'bar' => array(), // of class name
 84:             'blueScreen' => array(), // of callback
 85:         ),
 86:     );
 87: 
 88: 
 89:     public function loadConfiguration()
 90:     {
 91:         $container = $this->getContainerBuilder();
 92:         $config = $this->getConfig($this->defaults);
 93: 
 94:         if (isset($config['xhtml'])) {
 95:             $config['latte']['xhtml'] = $config['xhtml'];
 96:             unset($config['xhtml']);
 97:         }
 98:         $container->addDefinition('nette')->setClass('Nette\Bridges\Framework\NetteAccessor', array('@container'));
 99: 
100:         $this->validate($config, $this->defaults, 'nette');
101: 
102:         $this->setupCache($container);
103:         $this->setupHttp($container, $config['http']);
104:         $this->setupSession($container, $config['session']);
105:         $this->setupSecurity($container, $config['security']);
106:         $this->setupApplication($container, $config['application']);
107:         $this->setupRouting($container, $config['routing']);
108:         $this->setupMailer($container, $config['mailer']);
109:         $this->setupLatte($container, $config['latte']);
110:         $this->setupContainer($container, $config['container']);
111:     }
112: 
113: 
114:     private function setupCache(ContainerBuilder $container)
115:     {
116:         $container->addDefinition($this->prefix('cacheJournal'))
117:             ->setClass('Nette\Caching\Storages\FileJournal', array($container->expand('%tempDir%')));
118: 
119:         $container->addDefinition('cacheStorage') // no namespace for back compatibility
120:             ->setClass('Nette\Caching\Storages\FileStorage', array($container->expand('%tempDir%/cache')));
121: 
122:         if (class_exists('Nette\Caching\Storages\PhpFileStorage')) {
123:             $container->addDefinition($this->prefix('templateCacheStorage'))
124:                 ->setClass('Nette\Caching\Storages\PhpFileStorage', array($container->expand('%tempDir%/cache')))
125:                 ->addSetup('::trigger_error', array('Service templateCacheStorage is deprecated.', E_USER_DEPRECATED))
126:                 ->setAutowired(FALSE);
127:         }
128: 
129:         $container->addDefinition($this->prefix('cache'))
130:             ->setClass('Nette\Caching\Cache', array(1 => $container::literal('$namespace')))
131:             ->addSetup('::trigger_error', array('Service cache is deprecated.', E_USER_DEPRECATED))
132:             ->setParameters(array('namespace' => NULL))
133:             ->setAutowired(FALSE);
134:     }
135: 
136: 
137:     private function setupHttp(ContainerBuilder $container, array $config)
138:     {
139:         $this->validate($config, $this->defaults['http'], 'nette.http');
140: 
141:         $container->addDefinition($this->prefix('httpRequestFactory'))
142:             ->setClass('Nette\Http\RequestFactory')
143:             ->addSetup('setProxy', array($config['proxy']));
144: 
145:         $container->addDefinition('httpRequest') // no namespace for back compatibility
146:             ->setClass('Nette\Http\Request')
147:             ->setFactory('@Nette\Http\RequestFactory::createHttpRequest');
148: 
149:         $container->addDefinition('httpResponse') // no namespace for back compatibility
150:             ->setClass('Nette\Http\Response');
151: 
152:         $container->addDefinition($this->prefix('httpContext'))
153:             ->setClass('Nette\Http\Context');
154:     }
155: 
156: 
157:     private function setupSession(ContainerBuilder $container, array $config)
158:     {
159:         $session = $container->addDefinition('session') // no namespace for back compatibility
160:             ->setClass('Nette\Http\Session');
161: 
162:         if (isset($config['expiration'])) {
163:             $session->addSetup('setExpiration', array($config['expiration']));
164:         }
165: 
166:         if ($container->parameters['debugMode'] && $config['debugger']) {
167:             $session->addSetup('Tracy\Debugger::getBar()->addPanel(?)', array(
168:                 new Nette\DI\Statement('Nette\Bridges\HttpTracy\SessionPanel')
169:             ));
170:         }
171: 
172:         unset($config['expiration'], $config['autoStart'], $config['debugger']);
173:         if (!empty($config)) {
174:             $session->addSetup('setOptions', array($config));
175:         }
176:     }
177: 
178: 
179:     private function setupSecurity(ContainerBuilder $container, array $config)
180:     {
181:         $this->validate($config, $this->defaults['security'], 'nette.security');
182: 
183:         $container->addDefinition($this->prefix('userStorage'))
184:             ->setClass('Nette\Http\UserStorage');
185: 
186:         $user = $container->addDefinition('user') // no namespace for back compatibility
187:             ->setClass('Nette\Security\User');
188: 
189:         if ($container->parameters['debugMode'] && $config['debugger']) {
190:             $user->addSetup('Tracy\Debugger::getBar()->addPanel(?)', array(
191:                 new Nette\DI\Statement('Nette\Bridges\SecurityTracy\UserPanel')
192:             ));
193:         }
194: 
195:         if ($config['users']) {
196:             $usersList = $usersRoles = array();
197:             foreach ($config['users'] as $username => $data) {
198:                 $data = is_array($data) ? $data : array('password' => $data);
199:                 $this->validate($data, array('password' => NULL, 'roles' => NULL), $this->prefix("security.users.$username"));
200:                 $usersList[$username] = $data['password'];
201:                 $usersRoles[$username] = isset($data['roles']) ? $data['roles'] : NULL;
202:             }
203: 
204:             $container->addDefinition($this->prefix('authenticator'))
205:                 ->setClass('Nette\Security\SimpleAuthenticator', array($usersList, $usersRoles));
206:         }
207: 
208:         if ($config['roles'] || $config['resources']) {
209:             $authorizator = $container->addDefinition($this->prefix('authorizator'))
210:                 ->setClass('Nette\Security\Permission');
211:             foreach ($config['roles'] as $role => $parents) {
212:                 $authorizator->addSetup('addRole', array($role, $parents));
213:             }
214:             foreach ($config['resources'] as $resource => $parents) {
215:                 $authorizator->addSetup('addResource', array($resource, $parents));
216:             }
217:         }
218:     }
219: 
220: 
221:     private function setupApplication(ContainerBuilder $container, array $config)
222:     {
223:         $this->validate($config, $this->defaults['application'], 'nette.application');
224: 
225:         $application = $container->addDefinition('application') // no namespace for back compatibility
226:             ->setClass('Nette\Application\Application')
227:             ->addSetup('$catchExceptions', array($config['catchExceptions']))
228:             ->addSetup('$errorPresenter', array($config['errorPresenter']));
229: 
230:         if ($config['debugger']) {
231:             $application->addSetup('Nette\Bridges\ApplicationTracy\RoutingPanel::initializePanel');
232:         }
233: 
234:         $presenterFactory = $container->addDefinition($this->prefix('presenterFactory'))
235:             ->setClass('Nette\Application\PresenterFactory', array(
236:                 isset($container->parameters['appDir']) ? $container->parameters['appDir'] : NULL
237:             ));
238:         if ($config['mapping']) {
239:             $presenterFactory->addSetup('setMapping', array($config['mapping']));
240:         }
241:     }
242: 
243: 
244:     private function setupRouting(ContainerBuilder $container, array $config)
245:     {
246:         $this->validate($config, $this->defaults['routing'], 'nette.routing');
247: 
248:         $router = $container->addDefinition('router') // no namespace for back compatibility
249:             ->setClass('Nette\Application\Routers\RouteList');
250: 
251:         foreach ($config['routes'] as $mask => $action) {
252:             $router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?);', array($mask, $action));
253:         }
254: 
255:         if ($container->parameters['debugMode'] && $config['debugger']) {
256:             $container->getDefinition('application')->addSetup('Tracy\Debugger::getBar()->addPanel(?)', array(
257:                 new Nette\DI\Statement('Nette\Bridges\ApplicationTracy\RoutingPanel')
258:             ));
259:         }
260:     }
261: 
262: 
263:     private function setupMailer(ContainerBuilder $container, array $config)
264:     {
265:         $this->validate($config, $this->defaults['mailer'], 'nette.mailer');
266: 
267:         if (empty($config['smtp'])) {
268:             $container->addDefinition($this->prefix('mailer'))
269:                 ->setClass('Nette\Mail\SendmailMailer');
270:         } else {
271:             $container->addDefinition($this->prefix('mailer'))
272:                 ->setClass('Nette\Mail\SmtpMailer', array($config));
273:         }
274:     }
275: 
276: 
277:     private function setupLatte(ContainerBuilder $container, array $config)
278:     {
279:         $this->validate($config, $this->defaults['latte'], 'nette.latte');
280: 
281:         $latteFactory = $container->addDefinition($this->prefix('latteFactory'))
282:             ->setClass('Latte\Engine')
283:             ->addSetup('setTempDirectory', array($container->expand('%tempDir%/cache/latte')))
284:             ->addSetup('setAutoRefresh', array($container->parameters['debugMode']))
285:             ->addSetup('setContentType', array($config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML))
286:             ->setImplement('Nette\Bridges\ApplicationLatte\ILatteFactory');
287: 
288:         $container->addDefinition($this->prefix('templateFactory'))
289:             ->setClass('Nette\Bridges\ApplicationLatte\TemplateFactory');
290: 
291:         $latte = $container->addDefinition($this->prefix('latte')) // deprecated
292:             ->setClass('Latte\Engine')
293:             ->addSetup('setTempDirectory', array($container->expand('%tempDir%/cache/latte')))
294:             ->addSetup('setAutoRefresh', array($container->parameters['debugMode']))
295:             ->addSetup('setContentType', array($config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML))
296:             ->setAutowired(FALSE);
297: 
298:         foreach ($config['macros'] as $macro) {
299:             if (strpos($macro, '::') === FALSE && class_exists($macro)) {
300:                 $macro .= '::install';
301:             } else {
302:                 Validators::assert($macro, 'callable');
303:             }
304:             $latte->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', array('@self'));
305:             $latteFactory->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', array('@self'));
306:         }
307: 
308:         if (class_exists('Nette\Templating\FileTemplate')) {
309:             $container->addDefinition($this->prefix('template')) // deprecated
310:                 ->setClass('Nette\Templating\FileTemplate')
311:                 ->addSetup('registerFilter', array(new Nette\DI\Statement(array($latteFactory, 'create'))))
312:                 ->addSetup('registerHelperLoader', array('Nette\Templating\Helpers::loader'))
313:                 ->setAutowired(FALSE);
314:         }
315:     }
316: 
317: 
318:     private function setupContainer(ContainerBuilder $container, array $config)
319:     {
320:         $this->validate($config, $this->defaults['container'], 'nette.container');
321: 
322:         if ($config['accessors']) {
323:             $container->parameters['container']['accessors'] = TRUE;
324:         }
325:     }
326: 
327: 
328:     public function afterCompile(Nette\PhpGenerator\ClassType $class)
329:     {
330:         $initialize = $class->methods['initialize'];
331:         $container = $this->getContainerBuilder();
332:         $config = $this->getConfig($this->defaults);
333: 
334:         // debugger
335:         foreach (array('email', 'editor', 'browser', 'strictMode', 'maxLen', 'maxDepth', 'showLocation', 'scream') as $key) {
336:             if (isset($config['debugger'][$key])) {
337:                 $initialize->addBody('Tracy\Debugger::$? = ?;', array($key, $config['debugger'][$key]));
338:             }
339:         }
340: 
341:         if ($container->parameters['debugMode']) {
342:             if ($config['container']['debugger']) {
343:                 $config['debugger']['bar'][] = 'Nette\Bridges\DITracy\ContainerPanel';
344:             }
345: 
346:             foreach ((array) $config['debugger']['bar'] as $item) {
347:                 $initialize->addBody($container->formatPhp(
348:                     'Tracy\Debugger::getBar()->addPanel(?);',
349:                     Nette\DI\Compiler::filterArguments(array(is_string($item) ? new Nette\DI\Statement($item) : $item))
350:                 ));
351:             }
352:         }
353: 
354:         foreach ((array) $config['debugger']['blueScreen'] as $item) {
355:             $initialize->addBody($container->formatPhp(
356:                     'Tracy\Debugger::getBlueScreen()->addPanel(?);',
357:                 Nette\DI\Compiler::filterArguments(array($item))
358:             ));
359:         }
360: 
361:         if (!empty($container->parameters['tempDir']) && !$this->checkTempDir($container->expand('%tempDir%/cache'))) {
362:             $initialize->addBody('Nette\Caching\Storages\FileStorage::$useDirectories = FALSE;');
363:         }
364: 
365:         foreach ((array) $config['forms']['messages'] as $name => $text) {
366:             $initialize->addBody('Nette\Forms\Rules::$defaultMessages[Nette\Forms\Form::?] = ?;', array($name, $text));
367:         }
368: 
369:         if ($config['latte']['xhtml']) {
370:             $initialize->addBody('Nette\Utils\Html::$xhtml = ?;', array(TRUE));
371:         }
372: 
373:         if (PHP_SAPI !== 'cli') {
374:             if ($config['session']['autoStart'] === 'smart') {
375:                 $initialize->addBody('$this->getByType("Nette\Http\Session")->exists() && $this->getByType("Nette\Http\Session")->start();');
376:             } elseif ($config['session']['autoStart']) {
377:                 $initialize->addBody('$this->getByType("Nette\Http\Session")->start();');
378:             }
379: 
380:             if (isset($config['security']['frames']) && $config['security']['frames'] !== TRUE) {
381:                 $frames = $config['security']['frames'];
382:                 if ($frames === FALSE) {
383:                     $frames = 'DENY';
384:                 } elseif (preg_match('#^https?:#', $frames)) {
385:                     $frames = "ALLOW-FROM $frames";
386:                 }
387:                 $initialize->addBody('header(?);', array("X-Frame-Options: $frames"));
388:             }
389: 
390:             foreach ($config['http']['headers'] as $key => $value) {
391:                 if ($value != NULL) { // intentionally ==
392:                     $initialize->addBody('header(?);', array("$key: $value"));
393:                 }
394:             }
395:         }
396: 
397:         foreach ($container->findByTag('run') as $name => $on) {
398:             if ($on) {
399:                 $initialize->addBody('$this->getService(?);', array($name));
400:             }
401:         }
402: 
403:         if (!empty($config['container']['accessors'])) {
404:             $definitions = $container->definitions;
405:             ksort($definitions);
406:             foreach ($definitions as $name => $def) {
407:                 if (Nette\PhpGenerator\Helpers::isIdentifier($name)) {
408:                     $type = $def->implement ?: $def->class;
409:                     $class->addDocument("@property $type \$$name");
410:                 }
411:             }
412:         }
413: 
414:         $initialize->addBody('Nette\Utils\SafeStream::register();');
415:         $initialize->addBody('Nette\Reflection\AnnotationsParser::setCacheStorage($this->getByType("Nette\Caching\IStorage"));');
416:         $initialize->addBody('Nette\Reflection\AnnotationsParser::$autoRefresh = ?;', array($container->parameters['debugMode']));
417:     }
418: 
419: 
420:     private function checkTempDir($dir)
421:     {
422:         // checks whether directory is writable
423:         $uniq = uniqid('_', TRUE);
424:         if (!@mkdir("$dir/$uniq")) { // @ - is escalated to exception
425:             throw new Nette\InvalidStateException("Unable to write to directory '$dir'. Make this directory writable.");
426:         }
427: 
428:         // checks whether subdirectory is writable
429:         $isWritable = @file_put_contents("$dir/$uniq/_", '') !== FALSE; // @ - error is expected
430:         if ($isWritable) {
431:             unlink("$dir/$uniq/_");
432:         }
433:         rmdir("$dir/$uniq");
434:         return $isWritable;
435:     }
436: 
437: 
438:     private function validate(array $config, array $expected, $name)
439:     {
440:         if ($extra = array_diff_key($config, $expected)) {
441:             $extra = implode(", $name.", array_keys($extra));
442:             throw new Nette\InvalidStateException("Unknown option $name.$extra.");
443:         }
444:     }
445: 
446: }
447: 
Nette 2.2 API documentation generated by ApiGen 2.8.0