Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • none

Classes

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