Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • Compiler
  • CompilerExtension
  • Container
  • ContainerBuilder
  • ContainerLoader
  • DependencyChecker
  • Helpers
  • PhpGenerator
  • PhpReflection
  • ServiceDefinition
  • Statement

Exceptions

  • MissingServiceException
  • ServiceCreationException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\DI;
  9: 
 10: use Nette;
 11: use Nette\PhpGenerator\PhpLiteral;
 12: use Nette\Utils\Reflection;
 13: 
 14: 
 15: /**
 16:  * The DI helpers.
 17:  * @internal
 18:  */
 19: class Helpers
 20: {
 21:     use Nette\StaticClass;
 22: 
 23:     /**
 24:      * Expands %placeholders%.
 25:      * @param  mixed
 26:      * @param  array
 27:      * @param  bool|array
 28:      * @return mixed
 29:      * @throws Nette\InvalidArgumentException
 30:      */
 31:     public static function expand($var, array $params, $recursive = false)
 32:     {
 33:         if (is_array($var)) {
 34:             $res = [];
 35:             foreach ($var as $key => $val) {
 36:                 $res[$key] = self::expand($val, $params, $recursive);
 37:             }
 38:             return $res;
 39: 
 40:         } elseif ($var instanceof Statement) {
 41:             return new Statement(self::expand($var->getEntity(), $params, $recursive), self::expand($var->arguments, $params, $recursive));
 42: 
 43:         } elseif (!is_string($var)) {
 44:             return $var;
 45:         }
 46: 
 47:         $parts = preg_split('#%([\w.-]*)%#i', $var, -1, PREG_SPLIT_DELIM_CAPTURE);
 48:         $res = [];
 49:         $php = false;
 50:         foreach ($parts as $n => $part) {
 51:             if ($n % 2 === 0) {
 52:                 $res[] = $part;
 53: 
 54:             } elseif ($part === '') {
 55:                 $res[] = '%';
 56: 
 57:             } elseif (isset($recursive[$part])) {
 58:                 throw new Nette\InvalidArgumentException(sprintf('Circular reference detected for variables: %s.', implode(', ', array_keys($recursive))));
 59: 
 60:             } else {
 61:                 $val = $params;
 62:                 foreach (explode('.', $part) as $key) {
 63:                     if (is_array($val) && array_key_exists($key, $val)) {
 64:                         $val = $val[$key];
 65:                     } elseif ($val instanceof PhpLiteral) {
 66:                         $val = new PhpLiteral($val . '[' . var_export($key, true) . ']');
 67:                     } else {
 68:                         throw new Nette\InvalidArgumentException("Missing parameter '$part'.");
 69:                     }
 70:                 }
 71:                 if ($recursive) {
 72:                     $val = self::expand($val, $params, (is_array($recursive) ? $recursive : []) + [$part => 1]);
 73:                 }
 74:                 if (strlen($part) + 2 === strlen($var)) {
 75:                     return $val;
 76:                 }
 77:                 if ($val instanceof PhpLiteral) {
 78:                     $php = true;
 79:                 } elseif (!is_scalar($val)) {
 80:                     throw new Nette\InvalidArgumentException("Unable to concatenate non-scalar parameter '$part' into '$var'.");
 81:                 }
 82:                 $res[] = $val;
 83:             }
 84:         }
 85:         if ($php) {
 86:             $res = array_filter($res, function ($val) { return $val !== ''; });
 87:             $res = array_map(function ($val) { return $val instanceof PhpLiteral ? "($val)" : var_export((string) $val, true); }, $res);
 88:             return new PhpLiteral(implode(' . ', $res));
 89:         }
 90:         return implode('', $res);
 91:     }
 92: 
 93: 
 94:     /**
 95:      * Generates list of arguments using autowiring.
 96:      * @return array
 97:      * @throws ServiceCreationException
 98:      */
 99:     public static function autowireArguments(\ReflectionFunctionAbstract $method, array $arguments, $container)
100:     {
101:         $optCount = 0;
102:         $num = -1;
103:         $res = [];
104:         $methodName = Reflection::toString($method) . '()';
105: 
106:         foreach ($method->getParameters() as $num => $parameter) {
107:             $paramName = $parameter->getName();
108:             if (!$parameter->isVariadic() && array_key_exists($paramName, $arguments)) {
109:                 $res[$num] = $arguments[$paramName];
110:                 unset($arguments[$paramName], $arguments[$num]);
111:                 $optCount = 0;
112: 
113:             } elseif (array_key_exists($num, $arguments)) {
114:                 $res[$num] = $arguments[$num];
115:                 unset($arguments[$num]);
116:                 $optCount = 0;
117: 
118:             } elseif (($type = Reflection::getParameterType($parameter)) && !Reflection::isBuiltinType($type)) {
119:                 try {
120:                     $res[$num] = $container->getByType($type, false);
121:                 } catch (ServiceCreationException $e) {
122:                     throw new ServiceCreationException("{$e->getMessage()} (needed by $$paramName in $methodName)", 0, $e);
123:                 }
124:                 if ($res[$num] === null) {
125:                     if ($parameter->allowsNull()) {
126:                         $optCount++;
127:                     } elseif (class_exists($type) || interface_exists($type)) {
128:                         throw new ServiceCreationException("Service of type $type needed by $$paramName in $methodName not found. Did you register it in configuration file?");
129:                     } else {
130:                         throw new ServiceCreationException("Class $type needed by $$paramName in $methodName not found. Check type hint and 'use' statements.");
131:                     }
132:                 } else {
133:                     if ($container instanceof ContainerBuilder) {
134:                         $res[$num] = '@' . $res[$num];
135:                     }
136:                     $optCount = 0;
137:                 }
138: 
139:             } elseif (($type && $parameter->allowsNull()) || $parameter->isOptional() || $parameter->isDefaultValueAvailable()) {
140:                 // !optional + defaultAvailable = func($a = null, $b) since 5.4.7
141:                 // optional + !defaultAvailable = i.e. Exception::__construct, mysqli::mysqli, ...
142:                 $res[$num] = $parameter->isDefaultValueAvailable() ? Reflection::getParameterDefaultValue($parameter) : null;
143:                 $optCount++;
144: 
145:             } else {
146:                 throw new ServiceCreationException("Parameter $$paramName in $methodName has no class type hint or default value, so its value must be specified.");
147:             }
148:         }
149: 
150:         // extra parameters
151:         while (array_key_exists(++$num, $arguments)) {
152:             $res[$num] = $arguments[$num];
153:             unset($arguments[$num]);
154:             $optCount = 0;
155:         }
156:         if ($arguments) {
157:             throw new ServiceCreationException("Unable to pass specified arguments to $methodName.");
158:         }
159: 
160:         return $optCount ? array_slice($res, 0, -$optCount) : $res;
161:     }
162: 
163: 
164:     /**
165:      * Removes ... and process constants recursively.
166:      * @return array
167:      */
168:     public static function filterArguments(array $args)
169:     {
170:         foreach ($args as $k => $v) {
171:             if ($v === '...') {
172:                 unset($args[$k]);
173:             } elseif (is_string($v) && preg_match('#^[\w\\\\]*::[A-Z][A-Z0-9_]*\z#', $v, $m)) {
174:                 $args[$k] = constant(ltrim($v, ':'));
175:             } elseif (is_array($v)) {
176:                 $args[$k] = self::filterArguments($v);
177:             } elseif ($v instanceof Statement) {
178:                 $tmp = self::filterArguments([$v->getEntity()]);
179:                 $args[$k] = new Statement($tmp[0], self::filterArguments($v->arguments));
180:             }
181:         }
182:         return $args;
183:     }
184: 
185: 
186:     /**
187:      * Replaces @extension with real extension name in service definition.
188:      * @param  mixed
189:      * @param  string
190:      * @return mixed
191:      */
192:     public static function prefixServiceName($config, $namespace)
193:     {
194:         if (is_string($config)) {
195:             if (strncmp($config, '@extension.', 10) === 0) {
196:                 $config = '@' . $namespace . '.' . substr($config, 11);
197:             }
198:         } elseif ($config instanceof Statement) {
199:             return new Statement(
200:                 self::prefixServiceName($config->getEntity(), $namespace),
201:                 self::prefixServiceName($config->arguments, $namespace)
202:             );
203:         } elseif (is_array($config)) {
204:             foreach ($config as &$val) {
205:                 $val = self::prefixServiceName($val, $namespace);
206:             }
207:         }
208:         return $config;
209:     }
210: 
211: 
212:     /**
213:      * Returns an annotation value.
214:      * @return string|null
215:      */
216:     public static function parseAnnotation(\Reflector $ref, $name)
217:     {
218:         if (!Reflection::areCommentsAvailable()) {
219:             throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
220:         }
221:         $name = preg_quote($name, '#');
222:         if ($ref->getDocComment() && preg_match("#[\\s*]@$name(?:\\s++([^@]\\S*)?|$)#", trim($ref->getDocComment(), '/*'), $m)) {
223:             return isset($m[1]) ? $m[1] : '';
224:         }
225:     }
226: 
227: 
228:     /**
229:      * @return string|null
230:      */
231:     public static function getReturnType(\ReflectionFunctionAbstract $func)
232:     {
233:         if ($type = Reflection::getReturnType($func)) {
234:             return $type;
235:         } elseif ($type = preg_replace('#[|\s].*#', '', (string) self::parseAnnotation($func, 'return'))) {
236:             if ($type === 'object' || $type === 'mixed') {
237:                 return null;
238:             } elseif ($func instanceof \ReflectionMethod) {
239:                 return $type === 'static' || $type === '$this'
240:                     ? $func->getDeclaringClass()->getName()
241:                     : Reflection::expandClassName($type, $func->getDeclaringClass());
242:             } else {
243:                 return $type;
244:             }
245:         }
246:     }
247: 
248: 
249:     public static function normalizeClass($type)
250:     {
251:         return class_exists($type) || interface_exists($type)
252:             ? (new \ReflectionClass($type))->getName()
253:             : $type;
254:     }
255: }
256: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0