Packages

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

Classes

  • NArrayHash
  • NArrayList
  • NCallback
  • NConfigurator
  • NDateTime53
  • NFramework
  • NFreezableObject
  • NImage
  • NObject
  • NObjectMixin

Interfaces

  • IFreezable

Exceptions

  • ArgumentOutOfRangeException
  • DeprecatedException
  • DirectoryNotFoundException
  • FatalErrorException
  • FileNotFoundException
  • InvalidStateException
  • IOException
  • MemberAccessException
  • NotImplementedException
  • NotSupportedException
  • NStaticClassException
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004, 2011 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * Initial system DI container generator.
 17:  *
 18:  * @author     David Grudl
 19:  * @package Nette
 20:  */
 21: class NConfigurator extends NObject
 22: {
 23:     public static $instance;
 24: 
 25:     /** @var string */
 26:     public $defaultConfigFile = '%appDir%/config.neon';
 27: 
 28:     /** @var NDIContainer */
 29:     private $container;
 30: 
 31: 
 32: 
 33:     public function __construct($containerClass = 'NDIContainer')
 34:     {
 35:         self::$instance = $this;
 36:         $this->container = new $containerClass;
 37:         $this->container->addService('container', $this->container);
 38: 
 39:         foreach (get_class_methods($this) as $name) {
 40:             if (substr($name, 0, 13) === 'createService' ) {
 41:                 $this->container->addService(strtolower($name[13]) . substr($name, 14), array(__CLASS__, $name));
 42:             }
 43:         }
 44: 
 45:         defined('WWW_DIR') && $this->container->params['wwwDir'] = realpath(WWW_DIR);
 46:         defined('APP_DIR') && $this->container->params['appDir'] = realpath(APP_DIR);
 47:         defined('LIBS_DIR') && $this->container->params['libsDir'] = realpath(LIBS_DIR);
 48:         defined('TEMP_DIR') && $this->container->params['tempDir'] = realpath(TEMP_DIR);
 49:         $this->container->params['productionMode'] = self::detectProductionMode();
 50:         $this->container->params['consoleMode'] = PHP_SAPI === 'cli';
 51:     }
 52: 
 53: 
 54: 
 55:     /**
 56:      * Get initial instance of DI container.
 57:      * @return NDIContainer
 58:      */
 59:     public function getContainer()
 60:     {
 61:         return $this->container;
 62:     }
 63: 
 64: 
 65: 
 66:     /**
 67:      * Loads configuration from file and process it.
 68:      * @return NDIContainer
 69:      */
 70:     public function loadConfig($file, $section = NULL)
 71:     {
 72:         if ($file === NULL) {
 73:             $file = $this->defaultConfigFile;
 74:         }
 75:         $container = $this->container;
 76:         $file = $container->expand($file);
 77:         if (!is_file($file)) {
 78:             $file = preg_replace('#\.neon$#', '.ini', $file); // back compatibility
 79:         }
 80:         if ($section === NULL) {
 81:             if (PHP_SAPI === 'cli') {
 82:                 $section = NEnvironment::CONSOLE;
 83:             } else {
 84:                 $section = $container->params['productionMode'] ? NEnvironment::PRODUCTION : NEnvironment::DEVELOPMENT;
 85:             }
 86:         }
 87: 
 88:         $cache = new NCache($container->templateCacheStorage, 'Nette.Configurator');
 89:         $cacheKey = array((array) $container->params, $file, $section);
 90:         $cached = $cache->load($cacheKey);
 91:         if ($cached) {
 92:             require $cached['file'];
 93:             fclose($cached['handle']);
 94:             return $this->container;
 95:         }
 96: 
 97:         $config = NConfig::fromFile($file, $section);
 98:         $code = "<?php\n// source file $file\n\n";
 99: 
100:         // back compatibility with singular names
101:         foreach (array('service', 'variable') as $item) {
102:             if (isset($config[$item])) {
103:                 trigger_error(basename($file) . ": Section '$item' is deprecated; use plural form '{$item}s' instead.", E_USER_WARNING);
104:                 $config[$item . 's'] = $config[$item];
105:                 unset($config[$item]);
106:             }
107:         }
108: 
109:         // process services
110:         if (isset($config['services'])) {
111:             foreach ($config['services'] as $key => & $def) {
112:                 if (preg_match('#^Nette\\\\.*\\\\I?([a-zA-Z]+)$#', strtr($key, '-', '\\'), $m)) { // back compatibility
113:                     $m[1][0] = strtolower($m[1][0]);
114:                     trigger_error(basename($file) . ": service name '$key' has been renamed to '$m[1]'", E_USER_WARNING);
115:                     $key = $m[1];
116:                 }
117: 
118:                 if (is_array($def)) {
119:                     if (method_exists(__CLASS__, "createService$key") && !isset($def['factory']) && !isset($def['class'])) {
120:                         $def['factory'] = array(__CLASS__, "createService$key");
121:                     }
122: 
123:                     if (isset($def['option'])) {
124:                         $def['arguments'][] = $def['option'];
125:                     }
126: 
127:                     if (!empty($def['run'])) {
128:                         $def['tags'] = array('run');
129:                     }
130:                 }
131:             }
132:             $builder = new NDIContainerBuilder;
133:             $code .= '$builder = new '.get_class($builder).'; $builder->addDefinitions($container, '.var_export($config['services'], TRUE).');';
134:             unset($config['services']);
135:         }
136: 
137:         // consolidate variables
138:         if (!isset($config['variables'])) {
139:             $config['variables'] = array();
140:         }
141:         foreach ($config as $key => $value) {
142:             if (!in_array($key, array('variables', 'services', 'php', 'const', 'mode'))) {
143:                 $config['variables'][$key] = $value;
144:             }
145:         }
146: 
147:         // pre-expand variables at compile-time
148:         $variables = $config['variables'];
149:         array_walk_recursive($config, create_function('&$val', 'extract(NCFix::$vars['.NCFix::uses(array('variables'=>$variables)).'], EXTR_REFS);
150:             $val = NConfigurator::preExpand($val, $variables);
151:         '));
152: 
153:         // add variables
154:         foreach ($config['variables'] as $key => $value) {
155:             $code .= $this->generateCode('$container->params[?] = ?', $key, $value);
156:         }
157: 
158:         // PHP settings
159:         if (isset($config['php'])) {
160:             foreach ($config['php'] as $key => $value) {
161:                 if (is_array($value)) { // back compatibility - flatten INI dots
162:                     foreach ($value as $k => $v) {
163:                         $code .= $this->configurePhp("$key.$k", $v);
164:                     }
165:                 } else {
166:                     $code .= $this->configurePhp($key, $value);
167:                 }
168:             }
169:         }
170: 
171:         // define constants
172:         if (isset($config['const'])) {
173:             foreach ($config['const'] as $key => $value) {
174:                 $code .= $this->generateCode('define', $key, $value);
175:             }
176:         }
177: 
178:         // set modes - back compatibility
179:         if (isset($config['mode'])) {
180:             foreach ($config['mode'] as $mode => $state) {
181:                 trigger_error(basename($file) . ": Section 'mode' is deprecated; use '{$mode}Mode' in section 'variables' instead.", E_USER_WARNING);
182:                 $code .= $this->generateCode('$container->params[?] = ?', $mode . 'Mode', (bool) $state);
183:             }
184:         }
185: 
186:         // pre-loading
187:         $code .= self::preloadEnvironment($container);
188: 
189:         // auto-start services
190:         $code .= 'foreach ($container->getServiceNamesByTag("run") as $name => $foo) { $container->getService($name); }' . "\n";
191: 
192:         $cache->save($cacheKey, $code, array(
193:             NCache::FILES => $file,
194:         ));
195: 
196:         NLimitedScope::evaluate($code, array('container' => $container));
197:         return $this->container;
198:     }
199: 
200: 
201: 
202:     /********************* tools ****************d*g**/
203: 
204: 
205: 
206:     /**
207:      * Detects production mode by IP address.
208:      * @return bool
209:      */
210:     public static function detectProductionMode()
211:     {
212:         $addrs = array();
213:         if (PHP_SAPI === 'cli') {
214:             $addrs[] = getHostByName(php_uname('n'));
215:         }
216:         else {
217:             if (!isset($_SERVER['SERVER_ADDR']) && !isset($_SERVER['LOCAL_ADDR'])) {
218:                 return TRUE;
219:             }
220:             if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { // proxy server detected
221:                 $addrs = preg_split('#,\s*#', $_SERVER['HTTP_X_FORWARDED_FOR']);
222:             }
223:             if (isset($_SERVER['REMOTE_ADDR'])) {
224:                 $addrs[] = $_SERVER['REMOTE_ADDR'];
225:             }
226:             $addrs[] = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : $_SERVER['LOCAL_ADDR'];
227:         }
228:         foreach ($addrs as $addr) {
229:             $oct = explode('.', $addr);
230:             // 10.0.0.0/8   Private network
231:             // 127.0.0.0/8  Loopback
232:             // 169.254.0.0/16 & ::1  Link-Local
233:             // 172.16.0.0/12  Private network
234:             // 192.168.0.0/16  Private network
235:             if ($addr !== '::1' && (count($oct) !== 4 || ($oct[0] !== '10' && $oct[0] !== '127' && ($oct[0] !== '172' || $oct[1] < 16 || $oct[1] > 31)
236:                 && ($oct[0] !== '169' || $oct[1] !== '254') && ($oct[0] !== '192' || $oct[1] !== '168')))
237:             ) {
238:                 return TRUE;
239:             }
240:         }
241:         return FALSE;
242:     }
243: 
244: 
245: 
246:     public function configurePhp($name, $value)
247:     {
248:         if (!is_scalar($value)) {
249:             throw new InvalidStateException("Configuration value for directive '$name' is not scalar.");
250:         }
251: 
252:         switch ($name) {
253:         case 'include_path':
254:             return $this->generateCode('set_include_path', str_replace(';', PATH_SEPARATOR, $value));
255:         case 'ignore_user_abort':
256:             return $this->generateCode('ignore_user_abort', $value);
257:         case 'max_execution_time':
258:             return $this->generateCode('set_time_limit', $value);
259:         case 'date.timezone':
260:             return $this->generateCode('date_default_timezone_set', $value);
261:         }
262: 
263:         if (function_exists('ini_set')) {
264:             return $this->generateCode('ini_set', $name, $value);
265:         } elseif (ini_get($name) != $value && !NFramework::$iAmUsingBadHost) { // intentionally ==
266:             throw new NotSupportedException('Required function ini_set() is disabled.');
267:         }
268:     }
269: 
270: 
271: 
272:     private static function generateCode($statement)
273:     {
274:         $args = func_get_args();
275:         unset($args[0]);
276:         foreach ($args as &$arg) {
277:             $arg = var_export($arg, TRUE);
278:             $arg = preg_replace("#(?<!\\\)'%([\w-]+)%'#", '\$container->params[\'$1\']', $arg);
279:             $arg = preg_replace("#(?<!\\\)'(?:[^'\\\]|\\\.)*%(?:[^'\\\]|\\\.)*'#", '\$container->expand($0)', $arg);
280:         }
281:         if (strpos($statement, '?') === FALSE) {
282:             return $statement .= '(' . implode(', ', $args) . ");\n\n";
283:         }
284:         $a = strpos($statement, '?');
285:         $i = 1;
286:         while ($a !== FALSE) {
287:             $statement = substr_replace($statement, $args[$i], $a, 1);
288:             $a = strpos($statement, '?', $a + strlen($args[$i]));
289:             $i++;
290:         }
291:         return $statement . ";\n\n";
292:     }
293: 
294: 
295: 
296:     /**
297:      * Pre-expands %placeholders% in string.
298:      * @internal
299:      */
300:     public static function preExpand($s, array $params, $check = array())
301:     {
302:         if (!is_string($s)) {
303:             return $s;
304:         }
305: 
306:         $parts = preg_split('#%([\w.-]*)%#i', $s, -1, PREG_SPLIT_DELIM_CAPTURE);
307:         $res = '';
308:         foreach ($parts as $n => $part) {
309:             if ($n % 2 === 0) {
310:                 $res .= str_replace('%', '%%', $part);
311: 
312:             } elseif ($part === '') {
313:                 $res .= '%%';
314: 
315:             } elseif (isset($check[$part])) {
316:                 throw new InvalidArgumentException('Circular reference detected for variables: ' . implode(', ', array_keys($check)) . '.');
317: 
318:             } else {
319:                 try {
320:                     $val = NArrays::get($params, explode('.', $part));
321:                 } catch (InvalidArgumentException $e) {
322:                     $res .= "%$part%";
323:                     continue;
324:                 }
325:                 $val = self::preExpand($val, $params, $check + array($part => 1));
326:                 if (strlen($part) + 2 === strlen($s)) {
327:                     if (is_array($val)) {
328:                         array_walk_recursive($val, create_function('&$val', 'extract(NCFix::$vars['.NCFix::uses(array('params'=>$params,'check'=> $check,'part'=> $part)).'], EXTR_REFS);
329:                             $val = NConfigurator::preExpand($val, $params, $check + array($part => 1));
330:                         '));
331:                     }
332:                     return $val;
333:                 }
334:                 if (!is_scalar($val)) {
335:                     throw new InvalidArgumentException("Unable to concatenate non-scalar parameter '$part' into '$s'.");
336:                 }
337:                 $res .= $val;
338:             }
339:         }
340:         return $res;
341:     }
342: 
343: 
344: 
345:     /********************* service factories ****************d*g**/
346: 
347: 
348: 
349:     /**
350:      * @return NApplication
351:      */
352:     public static function createServiceApplication(NDIContainer $container, array $options = NULL)
353:     {
354:         $context = new NDIContainer;
355:         $context->addService('httpRequest', $container->httpRequest);
356:         $context->addService('httpResponse', $container->httpResponse);
357:         $context->addService('session', $container->session);
358:         $context->addService('presenterFactory', $container->presenterFactory);
359:         $context->addService('router', $container->router);
360: 
361:         NPresenter::$invalidLinkMode = $container->params['productionMode']
362:             ? NPresenter::INVALID_LINK_SILENT
363:             : NPresenter::INVALID_LINK_WARNING;
364: 
365:         $class = isset($options['class']) ? $options['class'] : 'NApplication';
366:         $application = new $class($context);
367:         $application->catchExceptions = $container->params['productionMode'];
368:         if ($container->session->exists()) {
369:         $application->onStartup[] = create_function('', 'extract(NCFix::$vars['.NCFix::uses(array('container'=>$container)).'], EXTR_REFS);
370:                 $container->session->start(); // opens already started session
371:             ');
372:         }
373:         return $application;
374:     }
375: 
376: 
377: 
378:     /**
379:      * @return IPresenterFactory
380:      */
381:     public static function createServicePresenterFactory(NDIContainer $container)
382:     {
383:         return new NPresenterFactory(
384:             isset($container->params['appDir']) ? $container->params['appDir'] : NULL,
385:             $container
386:         );
387:     }
388: 
389: 
390: 
391:     /**
392:      * @return IRouter
393:      */
394:     public static function createServiceRouter(NDIContainer $container)
395:     {
396:         return new NRouteList;
397:     }
398: 
399: 
400: 
401:     /**
402:      * @return NHttpRequest
403:      */
404:     public static function createServiceHttpRequest()
405:     {
406:         $factory = new NHttpRequestFactory;
407:         $factory->setEncoding('UTF-8');
408:         return $factory->createHttpRequest();
409:     }
410: 
411: 
412: 
413:     /**
414:      * @return NHttpResponse
415:      */
416:     public static function createServiceHttpResponse()
417:     {
418:         return new NHttpResponse;
419:     }
420: 
421: 
422: 
423:     /**
424:      * @return NHttpContext
425:      */
426:     public static function createServiceHttpContext(NDIContainer $container)
427:     {
428:         return new NHttpContext($container->httpRequest, $container->httpResponse);
429:     }
430: 
431: 
432: 
433:     /**
434:      * @return NSession
435:      */
436:     public static function createServiceSession(NDIContainer $container, array $options = NULL)
437:     {
438:         $session = new NSession($container->httpRequest, $container->httpResponse);
439:         $session->setOptions((array) $options);
440:         if (isset($options['expiration'])) {
441:             $session->setExpiration($options['expiration']);
442:         }
443:         return $session;
444:     }
445: 
446: 
447: 
448:     /**
449:      * @return NUser
450:      */
451:     public static function createServiceUser(NDIContainer $container)
452:     {
453:         $context = new NDIContainer;
454:         // copies services from $container and preserves lazy loading
455:         $context->addService('authenticator', create_function('', 'extract(NCFix::$vars['.NCFix::uses(array('container'=>$container)).'], EXTR_REFS);
456:             return $container->authenticator;
457:         '));
458:         $context->addService('authorizator', create_function('', 'extract(NCFix::$vars['.NCFix::uses(array('container'=>$container)).'], EXTR_REFS);
459:             return $container->authorizator;
460:         '));
461:         $context->addService('session', $container->session);
462:         return new NUser($context);
463:     }
464: 
465: 
466: 
467:     /**
468:      * @return ICacheStorage
469:      */
470:     public static function createServiceCacheStorage(NDIContainer $container)
471:     {
472:         if (!isset($container->params['tempDir'])) {
473:             throw new InvalidStateException("Service cacheStorage requires that parameter 'tempDir' contains path to temporary directory.");
474:         }
475:         $dir = $container->expand('%tempDir%/cache');
476:         umask(0000);
477:         @mkdir($dir, 0777); // @ - directory may exists
478:         return new NFileStorage($dir, $container->cacheJournal);
479:     }
480: 
481: 
482: 
483:     /**
484:      * @return ICacheStorage
485:      */
486:     public static function createServiceTemplateCacheStorage(NDIContainer $container)
487:     {
488:         if (!isset($container->params['tempDir'])) {
489:             throw new InvalidStateException("Service templateCacheStorage requires that parameter 'tempDir' contains path to temporary directory.");
490:         }
491:         $dir = $container->expand('%tempDir%/cache');
492:         umask(0000);
493:         @mkdir($dir, 0777); // @ - directory may exists
494:         return new NPhpFileStorage($dir);
495:     }
496: 
497: 
498: 
499:     /**
500:      * @return ICacheJournal
501:      */
502:     public static function createServiceCacheJournal(NDIContainer $container)
503:     {
504:         return new NFileJournal($container->params['tempDir']);
505:     }
506: 
507: 
508: 
509:     /**
510:      * @return IMailer
511:      */
512:     public static function createServiceMailer(NDIContainer $container, array $options = NULL)
513:     {
514:         if (empty($options['smtp'])) {
515:             return new NSendmailMailer;
516:         } else {
517:             return new NSmtpMailer($options);
518:         }
519:     }
520: 
521: 
522: 
523:     /**
524:      * @return NRobotLoader
525:      */
526:     public static function createServiceRobotLoader(NDIContainer $container, array $options = NULL)
527:     {
528:         $loader = new NRobotLoader;
529:         $loader->autoRebuild = isset($options['autoRebuild']) ? $options['autoRebuild'] : !$container->params['productionMode'];
530:         $loader->setCacheStorage($container->cacheStorage);
531:         if (isset($options['directory'])) {
532:             $loader->addDirectory($options['directory']);
533:         } else {
534:             foreach (array('appDir', 'libsDir') as $var) {
535:                 if (isset($container->params[$var])) {
536:                     $loader->addDirectory($container->params[$var]);
537:                 }
538:             }
539:         }
540:         $loader->register();
541:         return $loader;
542:     }
543: 
544: 
545: 
546:     public static function preloadEnvironment(NDIContainer $container)
547:     {
548:         $code = '';
549:         $dir = $container->expand('%tempDir%/cache');
550:         umask(0000);
551:         @mkdir($dir, 0777); // @ - directory may exists
552: 
553:         // checks whether directory is writable
554:         $uniq = uniqid('_', TRUE);
555:         umask(0000);
556:         if (!@mkdir("$dir/$uniq", 0777)) { // @ - is escalated to exception
557:             throw new InvalidStateException("Unable to write to directory '$dir'. Make this directory writable.");
558:         }
559: 
560:         // tests subdirectory mode
561:         $useDirs = @file_put_contents("$dir/$uniq/_", '') !== FALSE; // @ - error is expected
562:         @unlink("$dir/$uniq/_");
563:         @rmdir("$dir/$uniq"); // @ - directory may not already exist
564: 
565:         $code .= self::generateCode('NFileStorage::$useDirectories = ?', $useDirs);
566:         return $code;
567:     }
568: 
569: }
570: 
Nette Framework 2.0beta1 (for PHP 5.2) API API documentation generated by ApiGen 2.3.0