Namespaces

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

Classes

  • ArrayHash
  • ArrayList
  • Callback
  • Configurator
  • DateTime
  • Framework
  • FreezableObject
  • Image
  • Object
  • ObjectMixin

Interfaces

  • IFreezable

Exceptions

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