Packages

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

Classes

  • NConfigCompiler
  • NConfigCompilerExtension
  • NConfigHelpers
  • NConfigLoader
  • NConfigurator

Interfaces

  • IConfigAdapter
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 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\Config
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * DI container compiler.
 17:  *
 18:  * @author     David Grudl
 19:  *
 20:  * @property-read NConfigCompilerExtension[] $extensions
 21:  * @property-read NDIContainerBuilder $containerBuilder
 22:  * @property-read array $config
 23:  * @package Nette\Config
 24:  */
 25: class NConfigCompiler extends NObject
 26: {
 27:     /** @var NConfigCompilerExtension[] */
 28:     private $extensions = array();
 29: 
 30:     /** @var NDIContainerBuilder */
 31:     private $container;
 32: 
 33:     /** @var array */
 34:     private $config;
 35: 
 36:     /** @var array reserved section names */
 37:     private static $reserved = array('services' => 1, 'factories' => 1, 'parameters' => 1);
 38: 
 39: 
 40: 
 41:     /**
 42:      * Add custom configurator extension.
 43:      * @return NConfigCompiler  provides a fluent interface
 44:      */
 45:     public function addExtension($name, NConfigCompilerExtension $extension)
 46:     {
 47:         if (isset(self::$reserved[$name])) {
 48:             throw new InvalidArgumentException("Name '$name' is reserved.");
 49:         }
 50:         $this->extensions[$name] = $extension->setCompiler($this, $name);
 51:         return $this;
 52:     }
 53: 
 54: 
 55: 
 56:     /**
 57:      * @return array
 58:      */
 59:     public function getExtensions()
 60:     {
 61:         return $this->extensions;
 62:     }
 63: 
 64: 
 65: 
 66:     /**
 67:      * @return NDIContainerBuilder
 68:      */
 69:     public function getContainerBuilder()
 70:     {
 71:         return $this->container;
 72:     }
 73: 
 74: 
 75: 
 76:     /**
 77:      * Returns configuration without expanded parameters.
 78:      * @return array
 79:      */
 80:     public function getConfig()
 81:     {
 82:         return $this->config;
 83:     }
 84: 
 85: 
 86: 
 87:     /**
 88:      * @return string
 89:      */
 90:     public function compile(array $config, $className, $parentName)
 91:     {
 92:         $this->config = $config;
 93:         $this->container = new NDIContainerBuilder;
 94:         $this->processParameters();
 95:         $this->processExtensions();
 96:         $this->processServices();
 97:         return $this->generateCode($className, $parentName);
 98:     }
 99: 
100: 
101: 
102:     public function processParameters()
103:     {
104:         if (isset($this->config['parameters'])) {
105:             $this->container->parameters = $this->config['parameters'];
106:         }
107:     }
108: 
109: 
110: 
111:     public function processExtensions()
112:     {
113:         for ($i = 0; $slice = array_slice($this->extensions, $i, 1); $i++) {
114:             reset($slice)->loadConfiguration();
115:         }
116: 
117:         if ($extra = array_diff_key($this->config, self::$reserved, $this->extensions)) {
118:             $extra = implode("', '", array_keys($extra));
119:             throw new InvalidStateException("Found sections '$extra' in configuration, but corresponding extensions are missing.");
120:         }
121:     }
122: 
123: 
124: 
125:     public function processServices()
126:     {
127:         $this->parseServices($this->container, $this->config);
128: 
129:         foreach ($this->extensions as $name => $extension) {
130:             $this->container->addDefinition($name)
131:                 ->setClass('NDINestedAccessor', array('@container', $name))
132:                 ->setAutowired(FALSE);
133: 
134:             if (isset($this->config[$name])) {
135:                 $this->parseServices($this->container, $this->config[$name], $name);
136:             }
137:         }
138: 
139:         foreach ($this->container->getDefinitions() as $name => $def) {
140:             $factory = $name . 'Factory';
141:             if (!$def->shared && !$def->internal && !$this->container->hasDefinition($factory)) {
142:                 $this->container->addDefinition($factory)
143:                     ->setClass('NCallback', array('@container', NDIContainer::getMethodName($name, FALSE)))
144:                     ->setAutowired(FALSE)
145:                     ->tags = $def->tags;
146:             }
147:         }
148:     }
149: 
150: 
151: 
152:     public function generateCode($className, $parentName)
153:     {
154:         foreach ($this->extensions as $extension) {
155:             $extension->beforeCompile();
156:             $this->container->addDependency(NClassReflection::from($extension)->getFileName());
157:         }
158: 
159:         $classes[] = $class = $this->container->generateClass($parentName);
160:         $class->setName($className)
161:             ->addMethod('initialize');
162: 
163:         foreach ($this->extensions as $extension) {
164:             $extension->afterCompile($class);
165:         }
166: 
167:         $defs = $this->container->getDefinitions();
168:         ksort($defs);
169:         $list = array_keys($defs);
170:         foreach (array_reverse($defs, TRUE) as $name => $def) {
171:             if ($def->class === 'NDINestedAccessor' && ($found = preg_grep('#^'.$name.'\.#i', $list))) {
172:                 $list = array_diff($list, $found);
173:                 $def->class = $className . '_' . preg_replace('#\W+#', '_', $name);
174:                 $class->documents = preg_replace("#\\S+(?= \\$$name\\z)#", $def->class, $class->documents);
175:                 $classes[] = $accessor = new NPhpClassType($def->class);
176:                 foreach ($found as $item) {
177:                     if ($defs[$item]->internal) {
178:                         continue;
179:                     }
180:                     $short = substr($item, strlen($name)  + 1);
181:                     $accessor->addDocument($defs[$item]->shared
182:                         ? "@property {$defs[$item]->class} \$$short"
183:                         : "@method {$defs[$item]->class} create" . ucfirst("$short()"));
184:                 }
185:             }
186:         }
187: 
188:         return implode("\n\n\n", $classes);
189:     }
190: 
191: 
192: 
193:     /********************* tools ****************d*g**/
194: 
195: 
196: 
197:     /**
198:      * Parses section 'services' from configuration file.
199:      * @return void
200:      */
201:     public static function parseServices(NDIContainerBuilder $container, array $config, $namespace = NULL)
202:     {
203:         $services = isset($config['services']) ? $config['services'] : array();
204:         $factories = isset($config['factories']) ? $config['factories'] : array();
205:         $all = array_merge($services, $factories);
206: 
207:         uasort($all, create_function('$a, $b', '
208:             return strcmp(NConfigHelpers::isInheriting($a), NConfigHelpers::isInheriting($b));
209:         '));
210: 
211:         foreach ($all as $origName => $def) {
212:             $shared = array_key_exists($origName, $services);
213:             if ((string) (int) $origName === (string) $origName) {
214:                 $name = (string) (count($container->getDefinitions()) + 1);
215:             } elseif ($shared && array_key_exists($origName, $factories)) {
216:                 throw new NServiceCreationException("It is not allowed to use services and factories with the same name: '$origName'.");
217:             } else {
218:                 $name = ($namespace ? $namespace . '.' : '') . strtr($origName, '\\', '_');
219:             }
220: 
221:             if (($parent = NConfigHelpers::takeParent($def)) && $parent !== $name) {
222:                 $container->removeDefinition($name);
223:                 $definition = $container->addDefinition($name);
224:                 if ($parent !== NConfigHelpers::OVERWRITE) {
225:                     foreach ($container->getDefinition($parent) as $k => $v) {
226:                         $definition->$k = unserialize(serialize($v)); // deep clone
227:                     }
228:                 }
229:             } elseif ($container->hasDefinition($name)) {
230:                 $definition = $container->getDefinition($name);
231:                 if ($definition->shared !== $shared) {
232:                     throw new NServiceCreationException("It is not allowed to use service and factory with the same name '$name'.");
233:                 }
234:             } else {
235:                 $definition = $container->addDefinition($name);
236:             }
237:             try {
238:                 self::parseService($definition, $def, $shared);
239:             } catch (Exception $e) {
240:                 throw new NServiceCreationException("Service '$name': " . $e->getMessage(), NULL, $e);
241:             }
242:         }
243:     }
244: 
245: 
246: 
247:     /**
248:      * Parses single service from configuration file.
249:      * @return void
250:      */
251:     public static function parseService(NDIServiceDefinition $definition, $config, $shared = TRUE)
252:     {
253:         if ($config === NULL) {
254:             return;
255:         } elseif (!is_array($config)) {
256:             $config = array('class' => NULL, 'factory' => $config);
257:         }
258: 
259:         $known = $shared
260:             ? array('class', 'factory', 'arguments', 'setup', 'autowired', 'run', 'tags')
261:             : array('class', 'factory', 'arguments', 'setup', 'autowired', 'tags', 'internal', 'parameters');
262: 
263:         if ($error = array_diff(array_keys($config), $known)) {
264:             throw new InvalidStateException("Unknown key '" . implode("', '", $error) . "' in definition of service.");
265:         }
266: 
267:         $arguments = array();
268:         if (array_key_exists('arguments', $config)) {
269:             NValidators::assertField($config, 'arguments', 'array');
270:             $arguments = self::filterArguments($config['arguments']);
271:             $definition->setArguments($arguments);
272:         }
273: 
274:         if (array_key_exists('class', $config) || array_key_exists('factory', $config)) {
275:             $definition->class = NULL;
276:             $definition->factory = NULL;
277:         }
278: 
279:         if (array_key_exists('class', $config)) {
280:             NValidators::assertField($config, 'class', 'string|stdClass|null');
281:             if ($config['class'] instanceof stdClass) {
282:                 $definition->setClass($config['class']->value, self::filterArguments($config['class']->attributes));
283:             } else {
284:                 $definition->setClass($config['class'], $arguments);
285:             }
286:         }
287: 
288:         if (array_key_exists('factory', $config)) {
289:             NValidators::assertField($config, 'factory', 'callable|stdClass|null');
290:             if ($config['factory'] instanceof stdClass) {
291:                 $definition->setFactory($config['factory']->value, self::filterArguments($config['factory']->attributes));
292:             } else {
293:                 $definition->setFactory($config['factory'], $arguments);
294:             }
295:         }
296: 
297:         if (isset($config['setup'])) {
298:             if (NConfigHelpers::takeParent($config['setup'])) {
299:                 $definition->setup = array();
300:             }
301:             NValidators::assertField($config, 'setup', 'list');
302:             foreach ($config['setup'] as $id => $setup) {
303:                 NValidators::assert($setup, 'callable|stdClass', "setup item #$id");
304:                 if ($setup instanceof stdClass) {
305:                     NValidators::assert($setup->value, 'callable', "setup item #$id");
306:                     $definition->addSetup($setup->value, self::filterArguments($setup->attributes));
307:                 } else {
308:                     $definition->addSetup($setup);
309:                 }
310:             }
311:         }
312: 
313:         $definition->setShared($shared);
314:         if (isset($config['parameters'])) {
315:             NValidators::assertField($config, 'parameters', 'array');
316:             $definition->setParameters($config['parameters']);
317:         }
318: 
319:         if (isset($config['autowired'])) {
320:             NValidators::assertField($config, 'autowired', 'bool');
321:             $definition->setAutowired($config['autowired']);
322:         }
323: 
324:         if (isset($config['internal'])) {
325:             NValidators::assertField($config, 'internal', 'bool');
326:             $definition->setInternal($config['internal']);
327:         }
328: 
329:         if (isset($config['run'])) {
330:             $config['tags']['run'] = (bool) $config['run'];
331:         }
332: 
333:         if (isset($config['tags'])) {
334:             NValidators::assertField($config, 'tags', 'array');
335:             if (NConfigHelpers::takeParent($config['tags'])) {
336:                 $definition->tags = array();
337:             }
338:             foreach ($config['tags'] as $tag => $attrs) {
339:                 if (is_int($tag) && is_string($attrs)) {
340:                     $definition->addTag($attrs);
341:                 } else {
342:                     $definition->addTag($tag, $attrs);
343:                 }
344:             }
345:         }
346:     }
347: 
348: 
349: 
350:     /**
351:      * Removes ... and replaces entities with NDIStatement.
352:      * @return array
353:      */
354:     public static function filterArguments(array $args)
355:     {
356:         foreach ($args as $k => $v) {
357:             if ($v === '...') {
358:                 unset($args[$k]);
359:             } elseif ($v instanceof stdClass && isset($v->value, $v->attributes)) {
360:                 $args[$k] = new NDIStatement($v->value, self::filterArguments($v->attributes));
361:             }
362:         }
363:         return $args;
364:     }
365: 
366: }
367: 
Nette Framework 2.0.7 (for PHP 5.2, prefixed) API API documentation generated by ApiGen 2.8.0