1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\DI;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class Helpers
19: {
20:
21: 22: 23: 24: 25: 26: 27: 28:
29: public static function expand($var, array $params, $recursive = FALSE)
30: {
31: if (is_array($var)) {
32: $res = array();
33: foreach ($var as $key => $val) {
34: $res[$key] = self::expand($val, $params, $recursive);
35: }
36: return $res;
37:
38: } elseif ($var instanceof \stdClass || $var instanceof Statement) {
39: $res = clone $var;
40: foreach ($var as $key => $val) {
41: $res->$key = self::expand($val, $params, $recursive);
42: }
43: return $res;
44:
45: } elseif (!is_string($var)) {
46: return $var;
47: }
48:
49: $parts = preg_split('#%([\w.-]*)%#i', $var, -1, PREG_SPLIT_DELIM_CAPTURE);
50: $res = '';
51: foreach ($parts as $n => $part) {
52: if ($n % 2 === 0) {
53: $res .= $part;
54:
55: } elseif ($part === '') {
56: $res .= '%';
57:
58: } elseif (isset($recursive[$part])) {
59: throw new Nette\InvalidArgumentException(sprintf('Circular reference detected for variables: %s.', implode(', ', array_keys($recursive))));
60:
61: } else {
62: try {
63: $val = Nette\Utils\Arrays::get($params, explode('.', $part));
64: } catch (Nette\InvalidArgumentException $e) {
65: throw new Nette\InvalidArgumentException("Missing parameter '$part'.", 0, $e);
66: }
67: if ($recursive) {
68: $val = self::expand($val, $params, (is_array($recursive) ? $recursive : array()) + array($part => 1));
69: }
70: if (strlen($part) + 2 === strlen($var)) {
71: return $val;
72: }
73: if (!is_scalar($val)) {
74: throw new Nette\InvalidArgumentException("Unable to concatenate non-scalar parameter '$part' into '$var'.");
75: }
76: $res .= $val;
77: }
78: }
79: return $res;
80: }
81:
82:
83: 84: 85: 86: 87:
88: public static function autowireArguments(\ReflectionFunctionAbstract $method, array $arguments, $container)
89: {
90: $optCount = 0;
91: $num = -1;
92: $res = array();
93:
94: foreach ($method->getParameters() as $num => $parameter) {
95: if (array_key_exists($num, $arguments)) {
96: $res[$num] = $arguments[$num];
97: unset($arguments[$num]);
98: $optCount = 0;
99:
100: } elseif (array_key_exists($parameter->getName(), $arguments)) {
101: $res[$num] = $arguments[$parameter->getName()];
102: unset($arguments[$parameter->getName()]);
103: $optCount = 0;
104:
105: } elseif ($class = $parameter->getClassName()) {
106: $res[$num] = $container->getByType($class, FALSE);
107: if ($res[$num] === NULL) {
108: if ($parameter->allowsNull()) {
109: $optCount++;
110: } elseif (class_exists($class) || interface_exists($class)) {
111: throw new ServiceCreationException("Service of type {$class} needed by $method not found. Did you register it in configuration file?");
112: } else {
113: throw new ServiceCreationException("Class {$class} needed by $method not found. Check type hint and 'use' statements.");
114: }
115: } else {
116: if ($container instanceof ContainerBuilder) {
117: $res[$num] = '@' . $res[$num];
118: }
119: $optCount = 0;
120: }
121:
122: } elseif ($parameter->isOptional()) {
123:
124: $res[$num] = $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : NULL;
125: $optCount++;
126:
127: } else {
128: throw new ServiceCreationException("Parameter $parameter has no type hint, so its value must be specified.");
129: }
130: }
131:
132:
133: while (array_key_exists(++$num, $arguments)) {
134: $res[$num] = $arguments[$num];
135: unset($arguments[$num]);
136: $optCount = 0;
137: }
138: if ($arguments) {
139: throw new ServiceCreationException("Unable to pass specified arguments to $method.");
140: }
141:
142: return $optCount ? array_slice($res, 0, -$optCount) : $res;
143: }
144:
145:
146: 147: 148: 149:
150: public static function getInjectProperties(Nette\Reflection\ClassType $class, $container = NULL)
151: {
152: $res = array();
153: foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
154: $type = $property->getAnnotation('var');
155: if (!$property->getAnnotation('inject')) {
156: continue;
157:
158: } elseif (!$type) {
159: throw new Nette\InvalidStateException("Property $property has no @var annotation.");
160: }
161:
162: $type = Nette\Reflection\AnnotationsParser::expandClassName($type, self::getDeclaringClass($property));
163: if (!class_exists($type) && !interface_exists($type)) {
164: throw new Nette\InvalidStateException("Class or interface '$type' used in @var annotation at $property not found. Check annotation and 'use' statements.");
165: } elseif ($container && !$container->getByType($type, FALSE)) {
166: throw new ServiceCreationException("Service of type {$type} used in @var annotation at $property not found. Did you register it in configuration file?");
167: }
168: $res[$property->getName()] = $type;
169: }
170: return $res;
171: }
172:
173:
174: 175: 176: 177:
178: private static function getDeclaringClass(\ReflectionProperty $prop)
179: {
180: if (PHP_VERSION_ID >= 50400) {
181: foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
182: if ($trait->hasProperty($prop->getName())) {
183: return self::getDeclaringClass($trait->getProperty($prop->getName()));
184: }
185: }
186: }
187: return $prop->getDeclaringClass();
188: }
189:
190: }
191: