1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\DI;
13:
14: use Nette;
15:
16:
17:
18: 19: 20: 21: 22:
23: class ContainerBuilder extends Nette\Object
24: {
25:
26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
40: public function addDefinitions(IContainer $container, array $definitions)
41: {
42: foreach ($definitions as $name => $definition) {
43: if (is_scalar($definition)) {
44: if (substr($definition, 0, 1) === '@') {
45: $definition = array('alias' => substr($definition, 1));
46: } else {
47: $definition = array('class' => $definition);
48: }
49: }
50:
51: $arguments = isset($definition['arguments']) ? $definition['arguments'] : array();
52: $expander = function(&$val) use ($container) {
53: if (substr($val, 0, 1) === '@') {
54: $val = $container->getService(substr($val, 1));
55: } elseif (is_string($val)) {
56: $val = Nette\Utils\Strings::expand($val, $container->params);
57: }
58: };
59:
60: if (isset($definition['class']) || isset($definition['factory'])) {
61: if (isset($definition['class'])) {
62: $class = $definition['class'];
63: } else {
64: $class = NULL;
65: array_unshift($arguments, $definition['factory']);
66: }
67: $methods = isset($definition['methods']) ? $definition['methods'] : array();
68: $factory = function($container) use ($class, $arguments, $methods, $expander) {
69: array_walk_recursive($arguments, $expander);
70: if ($class) {
71: $class = Nette\Utils\Strings::expand($class, $container->params);
72: if ($arguments) {
73: $service = Nette\Reflection\ClassType::from($class)->newInstanceArgs($arguments);
74: } else {
75: $service = new $class;
76: }
77: } else {
78: $factory = $arguments[0]; $arguments[0] = $container;
79: $service = call_user_func_array($factory, $arguments);
80: }
81:
82: array_walk_recursive($methods, $expander);
83: foreach ($methods as $method) {
84: call_user_func_array(array($service, $method[0]), isset($method[1]) ? $method[1] : array());
85: }
86:
87: return $service;
88: };
89:
90: } elseif (isset($definition['alias'])) {
91: $factory = function($container) use ($definition) {
92: return $container->getService($definition['alias']);
93: };
94: } else {
95: throw new Nette\InvalidStateException("The definition of service '$name' is missing factory method.");
96: }
97:
98: if (isset($definition['tags'])) {
99: $tags = (array) $definition['tags'];
100: array_walk_recursive($tags, $expander);
101: } else {
102: $tags = NULL;
103: }
104: $container->addService($name, $factory, $tags);
105: }
106: }
107:
108:
109:
110: public function generateCode(array $definitions)
111: {
112: $code = '';
113: foreach ($definitions as $name => $definition) {
114: $name = $this->varExport($name);
115: if (is_scalar($definition)) {
116: if (substr($definition, 0, 1) === '@') {
117: $definition = array('alias' => substr($definition, 1));
118: } else {
119: $factory = $this->varExport($definition);
120: $code .= "\$container->addService($name, $factory);\n\n";
121: continue;
122: }
123: }
124:
125: if (isset($definition['class']) || isset($definition['factory'])) {
126: $arguments = $this->argsExport(isset($definition['arguments']) ? $definition['arguments'] : array());
127: $factory = "function(\$container) {\n\t";
128: $factory .= isset($definition['class'])
129: ? '$class = ' . $this->argsExport(array($definition['class'])) . '; $service = new $class(' . $arguments . ");\n"
130: : "\$service = call_user_func(\n\t\t" . $this->argsExport(array($definition['factory']))
131: . ",\n\t\t\$container" . ($arguments ? ",\n\t\t$arguments" : '') . "\n\t);\n";
132:
133: if (isset($definition['methods'])) {
134: foreach ($definition['methods'] as $method) {
135: $args = isset($method[1]) ? $this->argsExport($method[1]) : '';
136: $factory .= "\t\$service->$method[0]($args);\n";
137: }
138: }
139: $factory .= "\treturn \$service;\n}";
140:
141: } elseif (isset($definition['alias'])) {
142: $factory = $this->varExport($definition['alias']);
143: $factory = "function(\$container) {\n\treturn \$container->getService($factory);\n}";
144: } else {
145: throw new Nette\InvalidStateException("The definition of service '$name' is missing factory method.");
146: }
147:
148: $tags = isset($definition['tags']) ? $this->argsExport(array($definition['tags'])) : 'NULL';
149: $code .= "\$container->addService($name, $factory, $tags);\n\n";
150: }
151: return $code;
152: }
153:
154:
155:
156: private function argsExport($args)
157: {
158: $args = implode(', ', array_map(array($this, 'varExport'), $args));
159: $args = preg_replace("#(?<!\\\)'@(\w+)'#", '\$container->getService(\'$1\')', $args);
160: $args = preg_replace("#(?<!\\\)'%([\w-]+)%'#", '\$container->params[\'$1\']', $args);
161: $args = preg_replace("#(?<!\\\)'(?:[^'\\\]|\\\.)*%(?:[^'\\\]|\\\.)*'#", 'Nette\Utils\Strings::expand($0, \$container->params)', $args);
162: return $args;
163: }
164:
165:
166:
167: private function varExport($arg)
168: {
169: return preg_replace('#\n *#', ' ', var_export($arg, TRUE));
170: }
171:
172: }
173: